动态MemberExpression

时间:2011-03-16 06:17:57

标签: c# linq dynamic expression-trees

我想创建一个只知道字段名称的MemberExpression;例如:

public static Expression<Func<TModel, T>> GenerateMemberExpression<TModel, T>(string fieldName)
    {
        PropertyInfo fieldPropertyInfo;

        fieldPropertyInfo = typeof(TModel).GetProperty(fieldName);

        var entityParam = Expression.Parameter(typeof(TModel), "e"); // {e}
        var columnExpr = Expression.MakeMemberAccess(entityParam, fieldPropertyInfo); // {e.fieldName}
        var lambda = Expression.Lambda(columnExpr, entityParam) as Expression<Func<TModel, T>>; // {e => e.column}

        return lambda;
    }

上述问题是字段类型必须是强类型的。将“对象”作为字段类型传递不起作用。有没有办法生成这个?甚至动态LINQ似乎也不起作用。

2 个答案:

答案 0 :(得分:18)

您的代码存在许多问题:

  1. 您方法的参数名为fieldName,但您将获得属性
  2. 您正在使用非泛型Expression.Lambda方法生成表达式,如果传递给方法的类型参数T与属性不同,则可能会选择不合适的委托类型-类型。在这种情况下,从表达式到方法的返回类型的as强制转换将失败并计算为null。解决方案:使用generic Lambda方法和相应的类型参数。无需铸造。
  3. 如果你解决了第二个问题,当从属性类型到T可以进行安全的引用转换时,事情会正常工作,但是当需要更复杂的转换(如装箱/提升)时则不行。解决方案:必要时使用Expression.Convert方法。

  4. 以下是针对这些问题的示例更新:

    public static Expression<Func<TModel, T>> GenerateMemberExpression<TModel, T>
       (string propertyName)
    {
        var propertyInfo = typeof(TModel).GetProperty(propertyName);
    
        var entityParam = Expression.Parameter(typeof(TModel), "e"); 
        Expression columnExpr = Expression.Property(entityParam, propertyInfo);
    
        if (propertyInfo.PropertyType != typeof(T))
            columnExpr = Expression.Convert(columnExpr, typeof(T));
    
        return Expression.Lambda<Func<TModel, T>>(columnExpr, entityParam);
    }
    

    这将使以下所有呼叫成功:

    GenerateMemberExpression<FileInfo, string>("Name");
    GenerateMemberExpression<string, int>("Length");
    
    // Reference conversion
    GenerateMemberExpression<FileInfo, object>("Name");          
    
    //Boxing conversion
    GenerateMemberExpression<string, object>("Length");
    
    //Lifted conversion
    GenerateMemberExpression<string, int?>("Length");
    

答案 1 :(得分:2)

尝试在传递“对象”时手动转换字段值。例如:

var columnExpr = Expression.MakeMemberAccess(entityParam, fieldPropertyInfo); // {e.fieldName}
if (T.GetType().Equals(typeof(object)))
{
    columnExpr = Expression.Convert(columnExpr, typeof(object));
}

希望这会对你有所帮助。