在数据表对象上调用表达式

calling expression on datatable object

我正在尝试使用表达式树动态构建对我的数据的查询table,目前用于测试的数据由单个 table:

组成
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public Boolean IsSuperUser { get; set; }
    public DateTime RegisterDate { get; set; }
    public DateTime LastLoginDate { get; set; }
    public Int32 RandomIntValue { get; set; }
}

所以我写了一个代码来为我创建测试表达式:

 var column = generatedDatatable.Columns[0];

 ParameterExpression pe = Expression.Parameter(column.DataType, column.ColumnName);
 ConstantExpression value = Expression.Constant(14);
 Expression eq = Expression.Equal(pe, value);

 ParameterExpression pe2 = Expression.Parameter(column.DataType, column.ColumnName);
 ConstantExpression value2 = Expression.Constant(15);
 Expression eq2 = Expression.NotEqual(pe2, value2);

 Expression final = Expression.And(eq, eq2);

我的最终变量包括:

{((Id == 14) And (Id != 15))}

不,我有问题 - 如何在我的数据上调用该表达式table?或者我应该将 datatable 转换为 enumarable?

首先,不需要第二个 ParameterExpression 实例,您的参数必须是 User 类型的成员:

var parameter = Expression.Parameter(typeof(User), "source");
var memberOwnerParameter = Expression.PropertyOrField(source, propertyName); // propertyName is "Id" in your case.

ConstantExpression value = Expression.Constant(14);
Expression eq = Expression.Equal(memberOwnerParameter, value);

ConstantExpression value2 = Expression.Constant(15);
Expression eq2 = Expression.NotEqual(memberOwnerParameter, value2);

Expression final = Expression.And(eq, eq2);

然后如果您的来源是 IQueryable,那么:

var resultExpression = Expression.Lambda<Func<User, bool>>(final, memberOwnerParameter);
var result = source.Where(resultExpression);

否则,如果您的来源是 IEnumerable,那么:

var resultExpression = Expression.Lambda<Func<User, bool>>(final, memberOwnerParameter);
var resultDelegate = resultExpression.Compile();
var result = source.Where(resultDelegate);

然后您可以调用所需的 Linq 方法,例如 ToList()ToArray()First()Single()Select() 等等。 .

首先,正如另一个答案中已经提到的,您不需要第二个参数。但更重要的是,您的代码生成的内容未绑定到特定的 "column" 或 "property" - 生成的编译 lambda 类似于这样

Func<int, bool> predicate = (int Id) => (Id == 14 && Id != 15);

也就是说,这是一个接收int参数和returnsbool的函数。 Id 只是参数的名称,您可以传递任何 int 值。因此,它不能直接用作期望 Func<User, bool>IEnumerable<User> 上的 Where 条件,也不能直接用作期望 Func<DataRow, bool>IEnumerable<DataRow> 上的条件。

为了使其可用于 IEnumerable<User>,表达式必须建立在 User 类型的单个参数之上,如下所示

string memberName = ...;
var source = Expression.Parameter(typeof(User), "source");
var member = Expression.PropertyOrField(source, memberName); 
var cond1 = Expression.Equal(member, Expression.Constant(14));
var cond2 = Expression.NotEqual(member, Expression.Constant(15));
var cond = Expression.And(cond1, cond2);
var lambda = Expression.Lambda<Func<User, bool>>(cond, source);
var userFilter = lambda.Compile();

现在你可以这样使用了

List<User> users = ...;
var filteredUsers = users.Where(userFilter).ToList();