c# - 如何在表达式树中编写 string.Contains(someText)

标签 c# linq expression-trees

这是 the tutorial我正在学习表达式树。

我有超过 35 列要显示,但用户可以选择一次显示 10 列。因此,如果用户在搜索框中键入内容,我只想搜索用户可见的列。

SELECT FirstName, LastName, Address, ..., State
FROM Students
WHERE Id == @Id col1 AND (
      FirstName LIKE '%@searchText%' OR 
      LastName LIKE '%@searchText%' OR 
      Address LIKE '%@searchText%' OR 
      ...
      State LIKE '%@searchText%')

回到 Linq,这就是我试图完成它的方式:

var result = db.Students
    .Where(GetPredicate(id, listOfColumns))
    .ToList();

这是私有(private)方法:

private Expression<Func<Student, bool>> GetPredicate(int id, List<string> listOfColumns)
{
   ParameterExpression pe = Expression.Parameter(typeof(Student), "s");

   Expression left0 = Expression.Property(pe, "Id");
   Expression right0 = Expression.Constant(id);
   Expression e0 = Expression.Equal(left0, right0);

   //Here ... omitted code because it's not working...
   //

   var expr = Expression.Lambda<Func<Student, bool>>(e0, new ParameterExpression[] { pe });
        return expr;
}

如上所示,它工作得很好。但是,我什至编写此方法的原因是能够仅按用户选择的列进行过滤。

我希望能够根据 UI 中可见的列进行组合。

if(!string.IsNullOrEmpty(searchText))
{
   foreach (string columnName in columnList)
   {
       Expression col = Expression.Property(pe, columnName);
       Expression left = Expression.Call(pe, typeof(string).GetMethod("Contains"));
       Expression right = Expression.Constant(searchText);
       Expression e = Expression.IsTrue(left, right);
   }
}

我完全迷路了。我知道我需要访问字符串类的 Contains 方法然后我不知道下一步是什么。想法是得到这样的东西:

Where(d => d.Id == id && (d.FirstName.Contains(searchText) 
        || d.LastName.Contains(searchText) 
        || ...
        || d.State.Contains(searchText)))

感谢帮助

最佳答案

你非常接近,除了构造 Contains 的调用没有右边:

Expression col = Expression.Property(pe, columnName);
Expression contains = Expression.Call(
    pe
,   typeof(string).GetMethod(nameof(string.Contains), new Type[] { typeof(string)}) // Make a static field out of this
,   Expression.Constant(searchText) // Prepare a shared object before the loop
);

获得调用表达式后,将它们与 OrElse 组合以生成 lambda 的主体。您可以使用循环来实现,也可以使用 LINQ:

private static readonly MethodInfo Contains = typeof(string)
    .GetMethod(nameof(string.Contains), new Type[] { typeof(string)});

public static Expression<Func<Student,bool>> SearchPredicate(IEnumerable<string> properties, string searchText) {
    var param = Expression.Parameter(typeof(Student));
    var search = Expression.Constant(searchText);
    var components = properties
        .Select(propName => Expression.Call(Expression.Property(param, propName), Contains, search))
        .Cast<Expression>()
        .ToList();
    // This is the part that you were missing
    var body = components
        .Skip(1)
        .Aggregate(components[0], Expression.OrElse);
    return Expression.Lambda<Func<Student, bool>>(body, param);
}

关于c# - 如何在表达式树中编写 string.Contains(someText),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44209073/

相关文章:

c# - LINQ "' s' is not in scope"when creating where clause dynamically

.net - 我如何使用 C# lambda 表达式语法调用另一个表达式?

c# - 无法将类型 'System.Decimal' 的对象强制转换为类型 'System.String'

c# - 重写的表达式调用运算符方法...但原始节点没有运算符方法

c# - 如何优化 Shell32 方法调用?

C# 3.0 : Need to return duplicates from a List<>

c# - 使用 ComboBox 和 Column.Contains 的动态 Linq To Sql

c# - 如果字符串可解析为 int,则选择解析 int

c# - Web 应用程序中对 System.Windows.Forms 的资源和引用

C#:关于 protected 变量和内部变量的问题