C# 在表达式树中调用lambda表达式
我有一个SelectionCriteria类,用于基于PredicteBuilder构建实体框架查询表达式。在它的范围内,它工作得很好。我想扩展它,以便它可以查询字段是否包含子字符串。我的问题是,我看不到如何构建所需的表达式对象 我的实际课堂支持and,or,not,但它们与我的问题无关。因此,我简化了示例代码,只处理一个二进制操作:C# 在表达式树中调用lambda表达式,c#,lambda,expression-trees,linq-expressions,C#,Lambda,Expression Trees,Linq Expressions,我有一个SelectionCriteria类,用于基于PredicteBuilder构建实体框架查询表达式。在它的范围内,它工作得很好。我想扩展它,以便它可以查询字段是否包含子字符串。我的问题是,我看不到如何构建所需的表达式对象 我的实际课堂支持and,or,not,但它们与我的问题无关。因此,我简化了示例代码,只处理一个二进制操作: public class SelectionCriteria { public SelectionComparison selectionComparis
public class SelectionCriteria
{
public SelectionComparison selectionComparison { get; set; }
public string fieldName { get; set; }
public object fieldValue { get; set; }
public Expression<Func<T, bool>> constructSinglePredicate<T>()
{
var type = typeof(T);
if (type.GetProperty(this.fieldName) == null && type.GetField(this.fieldName) == null)
throw new MissingMemberException(type.Name, this.fieldName);
ExpressionType operation;
if (!operationMap.TryGetValue(this.selectionComparison, out operation))
throw new ArgumentOutOfRangeException("selectionComparison", this.selectionComparison, "Invalid filter operation");
var parameter = Expression.Parameter(type);
var member = Expression.PropertyOrField(parameter, this.fieldName);
var value = (this.fieldValue == null) ? Expression.Constant(null) : Expression.Constant(this.fieldValue, this.fieldValue.GetType());
try
{
var converted = (value.Type != member.Type)
? (Expression) Expression.Convert(value, member.Type)
: (Expression) value;
var comparison = Expression.MakeBinary(operation, member, converted);
var lambda = Expression.Lambda<Func<T, bool>>(comparison, parameter);
return lambda;
}
catch (Exception)
{
throw new InvalidOperationException(
String.Format("Cannot convert value \"{0}\" of type \"{1}\" to field \"{2}\" of type \"{3}\"", this.fieldValue,
value.Type, this.fieldName, member.Type));
}
}
private static Dictionary<SelectionComparison, ExpressionType> operationMap =
new Dictionary<SelectionComparison, ExpressionType>
{
{ SelectionComparison.Equal, ExpressionType.Equal },
{ SelectionComparison.GreaterThan, ExpressionType.GreaterThan },
};
}
public enum SelectionComparison
{
Equal,
GreaterThan,
Contains,
};
用法很简单:
var criteria = new SelectionCriteria
{
selectionComparison = SelectionComparison.GreaterThan,
fieldName = "worktobegindate",
fieldValue = DateTime.Now.AddDays(-2)
};
var predicate = criteria .constructPredicate<job>();
var jobs = myDbContext.jobs.Where(predicate);
所以,我的问题是——我需要一个方法,就像上面的ConstructionSinglePredictate一样,它返回一个表达式>,并应用一个.Contains
将Contains应用到一个字符串(给定一个要与之比较的字符串)很简单,但我很难弄清楚如何在表达式中执行相同的操作
想法?和往常一样,我的想法是错误的。我不需要对字符串调用方法的lambda,我需要从methodMap字典中提取MethodExpression:
public Expression<Func<T, bool>> constructMethodCallPredicate<T>()
{
var type = typeof(T);
if (type.GetProperty(this.fieldName) == null && type.GetField(this.fieldName) == null)
throw new MissingMemberException(type.Name, this.fieldName);
MethodInfo method;
if (!methodMap.TryGetValue(this.selectionComparison, out method))
throw new ArgumentOutOfRangeException("selectionComparison", this.selectionComparison, "Invalid filter operation");
var parameter = Expression.Parameter(type);
var member = Expression.PropertyOrField(parameter, this.fieldName);
var value = (this.fieldValue == null) ? Expression.Constant(null) : Expression.Constant(this.fieldValue, this.fieldValue.GetType());
try
{
var converted = (value.Type != member.Type)
? (Expression)Expression.Convert(value, member.Type)
: (Expression)value;
var methodExpression = Expression.Call(member, method, converted);
var lambda = Expression.Lambda<Func<T, bool>>(methodExpression, parameter);
return lambda;
}
catch (Exception)
{
throw new InvalidOperationException(
String.Format("Cannot convert value \"{0}\" of type \"{1}\" to field \"{2}\" of type \"{3}\"", this.fieldValue,
value.Type, this.fieldName, member.Type));
}
}
private static readonly Dictionary<SelectionComparison, MethodInfo> methodMap =
new Dictionary<SelectionComparison, MethodInfo>
{
{ SelectionComparison.Contains, typeof(string).GetMethod("Contains", new[] { typeof(string) }) },
{ SelectionComparison.StartsWith, typeof(string).GetMethod("StartsWith", new[] { typeof(string) }) },
{ SelectionComparison.EndsWith, typeof(string).GetMethod("EndsWith", new[] { typeof(string) }) },
};
public enum SelectionComparison
{
Equal,
NotEqual,
LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual,
Contains,
StartsWith,
EndsWith,
};
使用SqlFunctions.PatIndex进行实际的相似比较要复杂一点,PatIndex返回一个int,我需要将它包装在一个>0的表达式中,但它也可以正常工作