我想创建一个只知道字段名称的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似乎也不起作用。
答案 0 :(得分:18)
您的代码存在许多问题:
fieldName
,但您将获得属性。Expression.Lambda
方法生成表达式,如果传递给方法的类型参数T
与属性不同,则可能会选择不合适的委托类型-类型。在这种情况下,从表达式到方法的返回类型的as
强制转换将失败并计算为null
。解决方案:使用generic Lambda
方法和相应的类型参数。无需铸造。T
可以进行安全的引用转换时,事情会正常工作,但是当需要更复杂的转换(如装箱/提升)时则不行。解决方案:必要时使用Expression.Convert
方法。以下是针对这些问题的示例更新:
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));
}
希望这会对你有所帮助。