Dynamic MemberExpression

别等时光非礼了梦想. 提交于 2019-12-03 17:50:25

问题


I am wanting to create a MemberExpression knowing only the field name; eg:

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;
    }

The problem with the above is that the field type must be strongly typed. Passing "object" in as the field type doesn't work. Is there any way to generate this? Even Dynamic LINQ doesn't appear to work.


回答1:


There are a number of issues with your code:

  1. The parameter to your method is called fieldName, but you are getting a property out with it.
  2. You are using the non-generic Expression.Lambda method to generate the expression, which may choose an inappropriate delegate-type if the type-argument T passed to the method is not the same as the property-type. In this case, the as cast from the expression to the method's return-type will fail and evaluate to null. Solution: Use the generic Lambda method with the appropriate type-arguments. No casting required.
  3. If you solve the second issue, things will work fine when a safe reference-conversion is available from the property-type to T, but not when more complicated conversions such as boxing / lifting are required. Solution: Use the Expression.Convert method where necessary.

Here's an update to your sample that addresses these issues:

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);
}

This will make all of the following calls succeed:

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");



回答2:


Try manually converting the field value in case of passing an "object". For example:

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

Hope this will help you.



来源:https://stackoverflow.com/questions/5321726/dynamic-memberexpression

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!