【问题标题】:Modify Dynamic Property Selector Lambda修改动态属性选择器 Lambda
【发布时间】:2013-02-02 14:08:58
【问题描述】:

我编写了一个小方法,可以从字符串构建属性选择器 lambda - 类似于 Dynamic LINQ 所做的以及 Stack Overflow 上的一百万个其他示例。

例如,给定这个Expressions.PropertySelector<Type, PropertyType>("Source.Date"),如果编译,它将返回一个Func,类似于这个(Type) => type.Source.Date

无论如何,我遇到了一种情况,我不仅需要选择属性,还需要调用由其类型定义的方法。

例如,我想要这样的等价物:(Type) => Type.Source.Date.ToString("Y")。我知道我可能可以修改我的 PropertySelector 方法来检测方法调用并构建适当的表达式,但我很好奇是否有更好的方法。

对于那些好奇我为什么需要它的人:基本上它用于我正在构建的实体框架支持的存储库。我有一个方法允许调用者传递一个 lambda 来表示要分组的属性。调用者自己根据用户输入构造 lambda。所以我认为这样做是最好的方法。

但是,例如,如果要分组的属性是 DateTime。我会对其格式化的字符串进行分组。

处理这种情况的最佳方法是什么?理想情况下,我希望调用者在动态构建表达式后对其进行修改。

【问题讨论】:

  • 调用者究竟会如何修改它?你知道方法的名称只是一个字符串吗?还是在编译时就知道了?
  • @svick 我知道编译时方法的名称。但我也很好奇,如果我把它作为一个字符串来完成。

标签: c# .net entity-framework lambda expression-trees


【解决方案1】:

如果我理解正确,您有两种表达方式:一种从T1T2,第二种从T2T3,您想将它们组合成一个(从T1 到@987654327 @)。您可以使用LINQKit 来执行此操作:

public static Expression<Func<T1, T3>> CombineExpressions<T1, T2, T3>(
    Expression<Func<T1, T2>> first, Expression<Func<T2, T3>> second)
{
    Expression<Func<T1, T3>> result = x => second.Invoke(first.Invoke(x));
    // I think double Expand here is necessary because of Invoke inside Invoke
    return result.Expand().Expand();
}

例如:

Expression<Func<Person, DateTime>> getDateExpression =
    person => person.DOB;
Expression<Func<DateTime, string>> dateFormatExpression =
    date => date.ToString("Y");
Expression<Func<Person, string>> result =
    CombineExpressions(getDateExpression, dateFormatExpression);

这里,result 包含表达式 (Person x) =&gt; x.DOB.ToString("Y")

您可以动态构建一个或两个表达式,它不会改变组合的工作方式。

【讨论】:

  • 你我的朋友真是个天才!您的示例效果很好,尽管我不得不在 CombineExpressions 方法中将这一行 Expression&lt;Func&lt;T1, T3&gt;&gt; result = x =&gt; second.Invoke(first.Invoke(x)) 更改为 Expression&lt;Func&lt;T1, T3&gt;&gt; result = x =&gt; second.Compile().Invoke(first.Compile().Invoke(x))。我也不需要额外打电话给result.Expand().Expand();。没有它它工作得很好。如果您可以更新您的答案,我会将此答案标记为正确。另外,如果你有时间,你能解释一下Expand() 电话的好处吗?我实际上根本不需要参考 LINQKit。
  • @agarhy 如果您真的在使用实体框架,那么我很确定您的代码将无法正常工作。如果你使用Compile(),你就没有Expression,你只有一个Func。而且 EF 无法以此构建 SQL。
  • 它可以工作,但我相信它会在 EF 提取数据集后应用到内存中,因为它无法将 Func 转换为您提到的表达式。我之所以叫Compile(),是因为我认为InvokeExpression 的静态方法。还是我做错了什么?
  • @agarhy 如果你可以在内存中执行,那么你没有做错,只是不必要的复杂(你不需要Expressions,你可以使用Funcs直接地)。但是,如果您想将其作为 SQL 执行(我认为这是目标),那么您将需要 LINQKit 中的 Invoke()Expand() 扩展方法。
  • 我明白你的意思了。理想情况下,我想像你提到的那样执行 SQL。但是现在,当我像在您的示例中那样使用 LINQKit 时,出现此错误:LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method。看起来它在将日期转换为字符串时遇到了问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-04
  • 1970-01-01
  • 2013-10-25
  • 2014-03-08
  • 1970-01-01
  • 2014-02-18
相关资源
最近更新 更多