【问题标题】:Method that returns a Predicate < T > (where T is only known at runtime)返回 Predicate < T > 的方法(其中 T 仅在运行时已知)
【发布时间】:2013-08-30 08:20:15
【问题描述】:

我正在尝试将过滤器应用于 WPF 中的 DataGrid,并且过滤器属性需要一个谓词

例如:

dataGrid1.Filter = p => p.A_Field_Table1.Contains(textBox.Text);

但我的数据网格被反射填充,所以我只知道运行时数据网格内的对象类型。

然后我创建了一个动态生成 Predicate 的方法:

public static Predicate< T > GetPredicate< T >(string column, string valueP, T objSource, string table)
    {
        Type itemType = typeof(T);

        ParameterExpression predParam = Expression.Parameter(itemType, "p");
        Expression left = Expression.Property(predParam, itemType.GetProperty("A_" + column+ "_" + table));
        var valueStr= Expression.Constant(valueP);
        var typeOfStr = valueStr.Type;
        var containsMethod = typeOfStr.GetMethod("Contains", new [] { typeof(string) });
        var call = Expression.Call(left, containsMethod, valueStr);
        Func< T, bool > function = (Func< T, bool >)Expression.Lambda(call, new[] { predParam }).Compile();
        return new Predicate< T >(function);
    }

然后在接口上调用这个函数:

var dataGridItem = dataGrid.Items[0];
dataGrid1.Filter = Class_X.GetPredicate(columnRefName,textBox.Text,dataGridItem,tableRefName);

但是通用方法抛出一个异常,指出类型 T 是“对象”类型,即使 objSource 是 Model.TableName 类型。

我读了一些教程说 T 在运行时无法解析,那么我应该使用“动态”而不是泛型类型。

我已经尝试过使用“动态”类型,但是在将 Lambda 表达式转换为 Func 时出现异常。说我不能从 转换为 。

有没有更简单的方法来过滤由反射填充的数据网格?

【问题讨论】:

    标签: c# generics datagrid filter predicate


    【解决方案1】:

    在这种情况下,您不能使用泛型。 FilterFunc&lt;object, bool&gt;,所以:

    public static Predicate<object> GetPredicate(string column, string valueP, object objSource, string table)
    {
        Type itemType = objSource.GetType();
    
        ParameterExpression predParam = Expression.Parameter(typeof(object), "p");
        Expression left = Expression.Property(Expression.Convert(predParam, itemType), "A_" + column+ "_" + table);
        var valueStr= Expression.Constant(valueP);
        var typeOfStr = valueStr.Type;
        var containsMethod = typeOfStr.GetMethod("Contains", new [] { typeof(string) });
    
        var call = Expression.Call(left, containsMethod, valueStr);
    
        //To handle null values. It considers null == string.Empty
        //var left2 = Expression.Coalesce(left, Expression.Constant(string.Empty));
        //var call = Expression.Call(left2, containsMethod, valueStr);
    
        //If you want null values to be distinct from string.Empty, it's
        //much more complex. You'll need a temporary variable (left2)
        //where to put the value of the property, and then you can use the 
        //Expression.Condition (that is the ? : ternary operator) to 
        //test for null values
        //var left2 = Expression.Variable(typeof(string));
        //var assign = Expression.Assign(left2, left);
        //var notNull = Expression.NotEqual(left2, Expression.Constant(null));
        //var call = Expression.Call(left2, containsMethod, valueStr);
        //var condition = Expression.Condition(notNull, call, Expression.Constant(false));
        //var block = Expression.Block(new[] { left2 }, new Expression[] { assign, condition });
    
        Predicate<object> function = Expression.Lambda<Predicate<object>>(call, new[] { predParam }).Compile();
        return function;
    }
    

    “诀窍”是在返回的函数中将参数强制转换为“正确”类型(由objSource.GetType() 获得)

    请注意,您没有测试行属性中的 null 值(如果您尝试在 null 属性上使用 Contains,则为 NullReferenceException

    【讨论】:

    • 这就是问题所在,类型“T”是方法调用上的类型对象,但 objSource 变量是 Model.Tablename 类型... T 类型在运行时无法解析,所以我无法创建lambda func(因为它将使用 Model.Tablename 的一列在 lambda 上执行 Contains("text"))...
    • @RafaelA.M.S.重新改了代码...终于找到了你使用的Filtermsdn.microsoft.com/it-it/library/…,它是Predicate&lt;Object&gt; Filter
    • 如你所说,我没有测试行属性中的空值,并且在设置过滤器时得到NullReferenceException......如何解决它?
    • @RafaelA.M.S.添加这两行:var left2 = Expression.Coalesce(left, Expression.Constant(string.Empty)); var call = Expression.Call(left2, containsMethod, valueStr);。他们将使用?? 合并运算符并将null 视为string.Empty。如果您希望 nullstring.Empty “不同”,那就有点困难了。
    • 伟大的人,完美的工作!非常感谢你,你拯救了我的一天。 :D
    猜你喜欢
    • 2014-06-17
    • 1970-01-01
    • 2016-07-27
    • 2021-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多