【问题标题】:Using Expression vs Func使用表达式与函数
【发布时间】:2016-10-22 03:46:43
【问题描述】:

我有几个自动完成操作,下面列出了其中一个。我没有为每个自动完成 Where 方法编写不同的谓词,而是创建了一个 autoCompletePredicate。由于我有多个自动完成,我使用反射来获取特定自动完成所需的属性,并在我的autoCompletePredicate 中使用该属性。

我有以下工作正常的代码。

static string param1, param2;
static PropertyInfo[] properties;
static PropertyInfo prop1, prop2;

public IHttpActionResult GetAutComplete(string term, string dependent)
{
    int pagerSize = 10;

    properties = new MyObject().GetType().GetProperties();
    prop1 = properties.Where(p => p.Name.ToUpper().Equals("PROP1")).FirstOrDefault();
    prop2 = properties.Where(p => p.Name.ToUpper().Equals("PROP2")).FirstOrDefault();
    param1 = term;
    param2 = dependent;

    return Json(context.MyObject.Where(autoCompletePredicate).Select(r => new { label = r.PROP1 }).Distinct().OrderBy(r => r.label).Take(pagerSize).ToList());
}

Func<MyObject, int, bool> autoCompletePredicate = (GF, index) =>
{
    bool isFound = false;
    string term, dependent;

    term = prop1.GetValue(GF).ToString();
    dependent = prop2.GetValue(GF).ToString();

    var termFound = term.Contains(param1.ToUpper());
    var dependentFound = String.IsNullOrEmpty(param2) ? true : dependent.Contains(param2.ToUpper());

    isFound = termFound && dependentFound;

    return isFound;
};

如何将此代码更改为表达式。我尝试了以下编译好的代码,但在运行时出现以下错误

public static Expression<Func<MyObject, bool>> AutoCompleteExpression()
{
    return r => prop1.GetValue(r).ToString().Contains(param1.ToUpper()) && (String.IsNullOrEmpty(param2) ? true : prop2.GetValue(r).ToString().Contains(param2.ToUpper()));
}

"LINQ to Entities 无法识别方法 'System.Object GetValue(System.Object)' 方法,该方法不能翻译 到商店表达式中。”

我查看了以下post,这绝对是有道理的,但我不确定如何在我的场景中使用该示例(使用 Reflection 动态查找属性)。

另外,我想知道使用 Expression vs Func 有什么好处(特别是在我的情况下)

【问题讨论】:

  • 提供者正在尝试获取该表达式并从中创建 SQL,在这种情况下它不能这样做。您可以在 Linq-to-Objects 中执行这些表达式,但完全不清楚它应该做什么。
  • @DStanley 我在问题开始时提供了一些解释。请看是否有意义。

标签: c# linq expression func


【解决方案1】:

您正在尝试对字符串执行 Contains 方法并希望在 ExpressionTrees 中表示该方法,以下是您需要的代码:

创建字符串扩展方法 - 包含:(不区分大小写)

public static class StringExtensions
{
    public static bool Contains(this string source, string toCheck)
    {
        return source.IndexOf(toCheck, StringComparison.OrdinalIgnoreCase) >= 0;
    }
}

如下创建AutoCompleteExpression方法,它返回Func&lt;MyObject, bool&gt;

public static Func<MyObject, bool> AutoCompleteExpression()
{
   // Create ParameterExpression
   ParameterExpression parameterType = Expression.Parameter(typeof(MyObject), "object");

   // Create MemberExpression for Columns
   MemberExpression typeColumnProp1 = Expression.Property(parameterType, "PROP1");
   MemberExpression typeColumnProp2 = Expression.Property(parameterType, "PROP2");

   // Create MethoIndo
   MethodInfo containsMethodInfo = typeof(StringExtensions).GetMethod("Contains",new[] { typeof(string), typeof(string) },null);    

   // Create ConstantExpression values
   ConstantExpression constant1 = Expression.Constant(param1, typeof(string));
   ConstantExpression constant2 = Expression.Constant(param2, typeof(string));

   // Expression for calling methods
   MethodCallExpression expression1 = Expression.Call(null, containsMethodInfo, typeColumnProp1, constant1);
   MethodCallExpression expression2 = Expression.Call(null, containsMethodInfo, typeColumnProp2, constant2);

   // Combine `MethodCallExpression` to create Binary Expression
   BinaryExpression resultExpression = Expression.And(expression1,expression2);

    // Compile Expression tree to fetch `Func<MyObject, bool>`
   return Expression.Lambda<Func<MyObject, bool>>(resultExpression, parameterType).Compile();
 }

可以通过定义自定义扩展方法和使用 And / Or 组合表达式来增加更多灵活性

【讨论】:

  • 感谢您的回答。它真的帮助我理解表达式树。但是,我注意到您正在构建 Expression Tree 并将其作为 FUNC 返回。如果我返回FUNC,那么编写表达式树的意义何在。还有一件事我将您的方法返回为 Expression 但仍然收到此错误LINQ to Entities does not recognize the method 'Boolean Contains(System.String, System.String)' method, and this method cannot be translated into a store expression.
  • 关于第一个问题,请理解您创建表达式树的任何地方仍然会将其编译为 Func 以在 Linq to Entities 代码中使用它,因为没有 API 会直接获取表达式树,只有 IQueryable 获取表达式树直接地。因此,您可以从该方法返回表达式树,但仍需要编译为Func&lt;T,bool&gt;,最好是一次性处理,而不是每次都编译,因为这会影响性能。表达式树是不同的,因为你告诉系统你需要做什么,而不是你需要怎么做
  • 关于第二个问题,这是我的工作代码的版本,请确保您使用答案中发布的StringExtensions 类创建扩展方法,如果您的代码中没有包含的任何标准字符串默认情况下,可以访问它并给出正确的答案,然后此代码将起作用。否则,包含用于集合而不是字符串,这是一种解决方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-13
相关资源
最近更新 更多