将表达式的一部分定义为c#中的变量

我有以下代码:

public class MyClass { Expression<Func> Criteria {get; set;} } public class Customer { //.. public string Name {get; set;} } 

并使用如下:

 var c = new MyClass(); c.Criteria = x.Name.StartWith("SomeTexts"); 

有没有办法定义这样的东西:

 ? p = x=>x.Customer.Name; var c = new MyClass(); c.Criteria = p => p.StartWith("SomeTexts"); 

我使用Expression<Func>将它用作我的linq to entities查询中的where子句(EF代码优先)。

您可以使用以下帮助程序函数(可以为它们提供更好的名称,但这不是必需的):

 public static class ExpressionUtils { public static Expression> Bind(this Expression> source, Expression> resultSelector) { var body = new ParameterExpressionReplacer { source = resultSelector.Parameters[0], target = source.Body }.Visit(resultSelector.Body); var lambda = Expression.Lambda>(body, source.Parameters); return lambda; } public static Expression> ApplyTo(this Expression> source, Expression> innerSelector) { return innerSelector.Bind(source); } class ParameterExpressionReplacer : ExpressionVisitor { public ParameterExpression source; public Expression target; protected override Expression VisitParameter(ParameterExpression node) { return node == source ? target : base.VisitParameter(node); } } } 

让我们看一下样本表达式

 c.Criteria = x => x.Name.StartsWith("SomeTexts"); 

可以从两个不同的部分构建。

如果你有

 Expression> e = x => x.Name; 

然后

 c.Criteria = e.Bind(x => x.StartsWith("SomeTexts")); 

或者如果你有这个

 Expression> e = x => x.StartsWith("SomeTexts"); 

然后

 c.Criteria = e.ApplyTo((Customer x) => x.Name); 

如果你有两个表达式,那么你可以使用这两个函数中的任何一个,因为a.Bind(b)相当于b.ApplyTo(a)

您必须定义类型变量explicit,但下一代码将帮助您解决您的场景:

 // define new expression that get an Order object and returns string value Expression> p = x => x.Customer.Name; var c = new MyClass(); // Compile the expression to the Func then invoke it and call extra criteria c.Criteria = o => p.Compile().Invoke(o).StartsWith("SomeText"); 

没有表达式,有一点简单的解决方案:

 Func p = x => x.Customer.Name; var c = new MyClass(); c.Criteria = o => p(o).StartsWith("SomeText"); 

您还可以在MyClass使用Func<>而不是Expression<>

 public MyClass { Func Criteria {get; set;} } 

我没有看到在这里使用Expression的好处。 一个直的Func怎么样?

 public class MyClass { public Func Criteria { get; set; } } 

然后…

 var myCustomer = new MyClass { Criteria = (c, s) => c.Name.StartsWith(s) }; var customer = new Customer { Name = "Bob" }; var x = myCustomer.Criteria(customer, "B"); 

如果需要表达式,则可以使用LinqKit执行以下操作:

 Expression> p = x => x.Name; var c = new MyClass(); c.Criteria = x => p.Invoke(x).StartsWith("asd"); //Reuse p expression c.Criteria = c.Criteria.Expand(); 

Invoke是LinqKit提供的一种扩展方法,可以帮助您轻松地编写表达式。

在调用Expand方法之后, c.Criteria将包含一个与完成此操作完全相同的表达式:

 c.Criteria = x => x.Name.StartsWith("asd");