【问题标题】:Use C# extension method as predicate in linq query在 linq 查询中使用 C# 扩展方法作为谓词
【发布时间】:2016-02-05 08:15:15
【问题描述】:

我实现了扩展方法来规范化这篇文章中描述的字符串:LINQ Where Ignore Accentuation and Case

如果我做这样的事情,这个方法就像一个魅力:

employee.AsQueryable().Where(t=>t.Text.ToLower().RemoveDiacritics().Contains("ced"));

现在,我想通过动态生成 where 子句的谓词来更通用地使用它。

var values = filters.Select(f => f.Value is string && f.IgnoreAccent
                               ?((string)f.Value).RemoveDiacritics()
                               :f.Value).ToArray();

// Create a predicate expression
string predicate = filter.ToExpression(filters);

// Use the Where method of Dynamic Linq to filter the data
queryable = queryable.Where(predicate, values);

谓词将如下所示:

(Text.ToLower().RemoveDiacritics().Contains(@0))

由于未知原因,执行时收到以下错误消息:

“String”类型中不存在适用的方法“RemoveDiacritics”

但是,如果我在其他地方使用这种方法,它实际上可以正常工作。

有什么想法吗?

请注意,ToLower() 在这种情况下就像一个魅力。

提前感谢您的帮助!

编辑

这里是扩展方法的定义:

public static class StringExtension
{
    public static string RemoveDiacritics(this String s)
    {
        String normalizedString = s.Normalize(NormalizationForm.FormD);
        StringBuilder stringBuilder = new StringBuilder();

        for (int i = 0; i < normalizedString.Length; i++)
        {
            Char c = normalizedString[i];

            if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
                stringBuilder.Append(c);
        }

        return stringBuilder.ToString();
    }
}

【问题讨论】:

  • 您是否在依赖该方法的文件中包含方法扩展的命名空间?
  • 另外,您是否使用命名空间别名?
  • 在第一种情况下,您仍然有一个对象 t,而在第二种情况下,您将 f 转换为一个字符串。
  • 你需要展示你的扩展方法 RemoveDiacritics。它期待什么类型? ToLower 是字符串的扩展方法,如果您的扩展方法不以 (this string something... 那么这就是原因。
  • 如您所见,扩展方法需要一个字符串。对于命名空间,它是同一个项目的一部分,所以这不应该是一个问题,因为两个类都在同一个命名空间中。

标签: c# linq


【解决方案1】:
employee.AsQueryable().Where(t=>t.Text.ToLower().RemoveDiacritics().Contains("ced"));

可以替换为

employee.AsQueryable().Where(t=>t.Text.Equals("ced", StringComparison.OrdinalIgnoreCase));

速度更快,而且不考虑大小写。

【讨论】:

    【解决方案2】:

    Dynamic Linq 不支持扩展方法。 原因是Dynamic Linq使用了反射,实在很难找到扩展方法的实现,使用反射调用。所以动态 Linq 的作者并没有理会它。

    所以,你必须像普通静态方法一样调用扩展方法:

    var values = filters.Select(f => f.Value is string && f.IgnoreAccent
                               ?StringExtensions.RemoveDiacritics((string)f.Value)
                               :f.Value).ToArray();
    

    【讨论】:

      猜你喜欢
      • 2016-09-22
      • 1970-01-01
      • 1970-01-01
      • 2010-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多