如何创建返回布尔值的 Lambda 表达式的 C# 反射
How to create C# Reflection to Lambda Expression returning boolean
我有一个规范界面并且类:
public interface ISpecification<TEntity> where TEntity : class, new()
{
Expression<Func<TEntity, bool>> SatisfiedBy();
}
public abstract class Specification<TEntity> : ISpecification<TEntity> where TEntity : class, new()
{
public abstract Expression<Func<TEntity, bool>> SatisfiedBy();
public static Specification<TEntity> operator &(Specification<TEntity> leftSideSpecification, Specification<TEntity> rightSideSpecification)
{
return new AndSpecification<TEntity>(leftSideSpecification, rightSideSpecification);
}
public static Specification<TEntity> operator |(Specification<TEntity> leftSideSpecification, Specification<TEntity> rightSideSpecification)
{
return new OrSpecification<TEntity>(leftSideSpecification, rightSideSpecification);
}
public static Specification<TEntity> operator !(Specification<TEntity> specification)
{
return new NotSpecification<TEntity>(specification);
}
public static bool operator false(Specification<TEntity> specification)
{
return false;
}
public static bool operator true(Specification<TEntity> specification)
{
return true;
}
}
public class Table1BySpecification: Specification<Table1>
{
Propiedades Privadas
Expression<Func<Table1, bool>> _Expression = null;
public Table1BySpecification(Expression<Func<Table1, bool>> expression)
{
this._Expression = expression;
}
public override Expression<Func<Table1, bool>> SatisfiedBy()
{
return this._Expression;
}
}
我创建了一个 Table1BySpecification,因此我可以 运行 从通用函数...
public IEnumerable<TEntity> GetBySpecification(string propertyName, object propertyValue, propertyOperator ){
ISpecification<Table1> Specification = new Table1BySpecification(t1 => t1.name == "test_name");
context.CreateDbSet<Table1>().Where(Specification.SatisfiedBy())
}
这适用于 Table1 实体,但我想改用 TEntity,并通过反射使用动态规范。也许我可以有类似的东西:
public IEnumerable<TEntity> GetBySpecification(string propertyName = "name", object propertyValue = "test_name", string propertyOperator = "==" ){
var source = typeof(TEntity);
var t = Expression.Parameter( source, "t" );
var sourceProperty = Expression.MakeMemberAccess( arg, source.GetProperty( propertyName ) );
PropertyInfo propertyField = type.GetProperty(propertyName);
Type propertyType = propertyField.GetType();
PropertyInfo[] props = typeof(TEntity).GetProperties();
foreach (PropertyInfo prop in props)
{
var displayAttribute = prop.GetCustomAttributes(false).FirstOrDefault(a => a.GetType() == propertyType);
if (displayAttribute != null)
{
var parameterExpression = Expression.Parameter(typeof(TEntity), "x");
var memberExpression = Expression.PropertyOrField(parameterExpression, prop.Name);
var memberExpressionConversion = Expression.Convert(memberExpression, typeof(object));
var lambda = Expression.Lambda<Func<TEntity, object>>(memberExpressionConversion, parameterExpression);
}
}
ISpecification<TEntity> Specification = new EntityByCustomSpecification<TEntity>(***Reflection_Expression***);
context.CreateDbSet<TEntity>().Where(Specification.SatisfiedBy()),
}
我不知道这段代码是否可以作为创建解决方案的一部分(Reflection_Expression)至少在 propertyName 变量方面。
我真的无法创建 (Reflection_Expression) 作为 lambda 表达式,最后得到 Reflection_Expression执行...
(t1 => t1.name == "test_name")
...当TEntity为t1时,propertyName为name,其值propertyValue为"test_name",运算符propertyOperator为“==”
有什么帮助吗???
非常感谢!
给定
public class EntityByCustomSpecification<TEntity> : Specification<TEntity> where TEntity : class, new()
{
Expression<Func<TEntity, bool>> _Expression = null;
public EntityByCustomSpecification(Expression<Func<TEntity, bool>> expression)
{
this._Expression = expression;
}
public override Expression<Func<TEntity, bool>> SatisfiedBy()
{
return this._Expression;
}
}
(不知道你有没有)
你想要的是:
public IEnumerable<TEntity> GetBySpecification<TEntity>(object propertyValue, string propertyName = "name", ExpressionType operation = ExpressionType.Equal) where TEntity : class, new()
{
ParameterExpression par = Expression.Parameter(typeof(TEntity));
Expression left = Expression.PropertyOrField(par, propertyName);
Expression right = Expression.Constant(propertyValue, left.Type);
Expression comparison;
try
{
comparison = Expression.MakeBinary(operation, left, right);
}
catch (InvalidOperationException)
{
// string case, for example
Type icomparable = typeof(IComparable<>).MakeGenericType(left.Type);
if (!left.Type.GetInterfaces().Any(x => x == icomparable))
{
throw;
}
InterfaceMapping interfaceMap = left.Type.GetInterfaceMap(icomparable);
int ix = Array.FindIndex(interfaceMap.InterfaceMethods, x => x.Name == "CompareTo");
MethodInfo method = interfaceMap.TargetMethods[ix];
// left.CompareTo(right) [operation] 0
comparison = Expression.MakeBinary(operation, Expression.Call(left, method, right), Expression.Constant(0));
}
if (comparison.Type != typeof(bool))
{
throw new ArgumentException("operationType");
}
Expression<Func<TEntity, bool>> lambda = Expression.Lambda<Func<TEntity, bool>>(comparison, par);
ISpecification<TEntity> specification = new EntityByCustomSpecification<TEntity>(lambda);
var result = context.Set<TEntity>().Where(specification.SatisfiedBy());
return result;
}
请注意,为了使其更简单,它接受 ExpressionType
而不是 string propertyOperator
。 ExpressionType
包含所有比较运算符(<
、<=
、==
、>=
、>
),以及您可以忽略的数学运算符(+
、-
...)。您可以轻松编写一个方法,给定 string
returns 正确的 ExpressionType
.
我已经更正了可空类型的错误。我通过 IComparable<T>
接口添加了对 string
的支持。
我有一个规范界面并且类:
public interface ISpecification<TEntity> where TEntity : class, new()
{
Expression<Func<TEntity, bool>> SatisfiedBy();
}
public abstract class Specification<TEntity> : ISpecification<TEntity> where TEntity : class, new()
{
public abstract Expression<Func<TEntity, bool>> SatisfiedBy();
public static Specification<TEntity> operator &(Specification<TEntity> leftSideSpecification, Specification<TEntity> rightSideSpecification)
{
return new AndSpecification<TEntity>(leftSideSpecification, rightSideSpecification);
}
public static Specification<TEntity> operator |(Specification<TEntity> leftSideSpecification, Specification<TEntity> rightSideSpecification)
{
return new OrSpecification<TEntity>(leftSideSpecification, rightSideSpecification);
}
public static Specification<TEntity> operator !(Specification<TEntity> specification)
{
return new NotSpecification<TEntity>(specification);
}
public static bool operator false(Specification<TEntity> specification)
{
return false;
}
public static bool operator true(Specification<TEntity> specification)
{
return true;
}
}
public class Table1BySpecification: Specification<Table1>
{
Propiedades Privadas
Expression<Func<Table1, bool>> _Expression = null;
public Table1BySpecification(Expression<Func<Table1, bool>> expression)
{
this._Expression = expression;
}
public override Expression<Func<Table1, bool>> SatisfiedBy()
{
return this._Expression;
}
}
我创建了一个 Table1BySpecification,因此我可以 运行 从通用函数...
public IEnumerable<TEntity> GetBySpecification(string propertyName, object propertyValue, propertyOperator ){
ISpecification<Table1> Specification = new Table1BySpecification(t1 => t1.name == "test_name");
context.CreateDbSet<Table1>().Where(Specification.SatisfiedBy())
}
这适用于 Table1 实体,但我想改用 TEntity,并通过反射使用动态规范。也许我可以有类似的东西:
public IEnumerable<TEntity> GetBySpecification(string propertyName = "name", object propertyValue = "test_name", string propertyOperator = "==" ){
var source = typeof(TEntity);
var t = Expression.Parameter( source, "t" );
var sourceProperty = Expression.MakeMemberAccess( arg, source.GetProperty( propertyName ) );
PropertyInfo propertyField = type.GetProperty(propertyName);
Type propertyType = propertyField.GetType();
PropertyInfo[] props = typeof(TEntity).GetProperties();
foreach (PropertyInfo prop in props)
{
var displayAttribute = prop.GetCustomAttributes(false).FirstOrDefault(a => a.GetType() == propertyType);
if (displayAttribute != null)
{
var parameterExpression = Expression.Parameter(typeof(TEntity), "x");
var memberExpression = Expression.PropertyOrField(parameterExpression, prop.Name);
var memberExpressionConversion = Expression.Convert(memberExpression, typeof(object));
var lambda = Expression.Lambda<Func<TEntity, object>>(memberExpressionConversion, parameterExpression);
}
}
ISpecification<TEntity> Specification = new EntityByCustomSpecification<TEntity>(***Reflection_Expression***);
context.CreateDbSet<TEntity>().Where(Specification.SatisfiedBy()),
}
我不知道这段代码是否可以作为创建解决方案的一部分(Reflection_Expression)至少在 propertyName 变量方面。 我真的无法创建 (Reflection_Expression) 作为 lambda 表达式,最后得到 Reflection_Expression执行...
(t1 => t1.name == "test_name")
...当TEntity为t1时,propertyName为name,其值propertyValue为"test_name",运算符propertyOperator为“==”
有什么帮助吗???
非常感谢!
给定
public class EntityByCustomSpecification<TEntity> : Specification<TEntity> where TEntity : class, new()
{
Expression<Func<TEntity, bool>> _Expression = null;
public EntityByCustomSpecification(Expression<Func<TEntity, bool>> expression)
{
this._Expression = expression;
}
public override Expression<Func<TEntity, bool>> SatisfiedBy()
{
return this._Expression;
}
}
(不知道你有没有)
你想要的是:
public IEnumerable<TEntity> GetBySpecification<TEntity>(object propertyValue, string propertyName = "name", ExpressionType operation = ExpressionType.Equal) where TEntity : class, new()
{
ParameterExpression par = Expression.Parameter(typeof(TEntity));
Expression left = Expression.PropertyOrField(par, propertyName);
Expression right = Expression.Constant(propertyValue, left.Type);
Expression comparison;
try
{
comparison = Expression.MakeBinary(operation, left, right);
}
catch (InvalidOperationException)
{
// string case, for example
Type icomparable = typeof(IComparable<>).MakeGenericType(left.Type);
if (!left.Type.GetInterfaces().Any(x => x == icomparable))
{
throw;
}
InterfaceMapping interfaceMap = left.Type.GetInterfaceMap(icomparable);
int ix = Array.FindIndex(interfaceMap.InterfaceMethods, x => x.Name == "CompareTo");
MethodInfo method = interfaceMap.TargetMethods[ix];
// left.CompareTo(right) [operation] 0
comparison = Expression.MakeBinary(operation, Expression.Call(left, method, right), Expression.Constant(0));
}
if (comparison.Type != typeof(bool))
{
throw new ArgumentException("operationType");
}
Expression<Func<TEntity, bool>> lambda = Expression.Lambda<Func<TEntity, bool>>(comparison, par);
ISpecification<TEntity> specification = new EntityByCustomSpecification<TEntity>(lambda);
var result = context.Set<TEntity>().Where(specification.SatisfiedBy());
return result;
}
请注意,为了使其更简单,它接受 ExpressionType
而不是 string propertyOperator
。 ExpressionType
包含所有比较运算符(<
、<=
、==
、>=
、>
),以及您可以忽略的数学运算符(+
、-
...)。您可以轻松编写一个方法,给定 string
returns 正确的 ExpressionType
.
我已经更正了可空类型的错误。我通过 IComparable<T>
接口添加了对 string
的支持。