【问题标题】:Can't build lambda Expression with unknown type of a property无法使用未知类型的属性构建 lambda 表达式
【发布时间】:2016-11-12 17:49:42
【问题描述】:

我正在构建一个辅助方法,该方法基于一个属性返回一个表达式,该属性可用于 orderby 或 where 等。在 linq to entity 操作中。

我不会预先知道属性的类型,所以我将其声明为对象和动态,并且还尝试使用Expression.Convert,但它不适用于非字符串类型的属性。

我正在使用的不是字符串的当前属性类型是int?,我得到的错误是

“System.Nullable`1[System.Int32]”类型的表达式不能用于返回类型“System.Object”;

代码:

var param = Expression.Parameter(typeof(Employee), "x");
MemberExpression propExp = Expression.Property(param, "somePropertyName");
Expression.Lambda<Func<Employee, object>>(propExpression, param);

正如我所说,我在上面使用了 object 和 dynamic 并获得了相同的结果。我也尝试将其转换为正确的类型,但这不起作用:

Expression conversion = Expression.Convert(propExp, ((PropertyInfo)propExp.Member).PropertyType)

当我处于调试模式并尝试此操作时,Expression.Lambda(conversiona, param),它似乎可以工作

{x => Convert(x.EmployeeNo)}
Body: {Convert(x.EmployeeNo)}
CanReduce: false
DebugView: ".Lambda #Lambda1<System.Func`2[xx.DomainModel.Entities.Employee,System.Nullable`1[System.Int32]]>(xx.DomainModel.Entities.Employee $x)\r\n{\r\n    (System.Nullable`1[System.Int32])$x.EmployeeNo\r\n}"
Name: null
NodeType: Lambda
Parameters: Count = 1
ReturnType: {Name = "Nullable`1" FullName = "System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}
TailCall: false
Type: {Name = "Func`2" FullName = "System.Func`2[[xx.DomainModel.Entities.Employee, Fng.Facts.DomainModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}

...但是当我在 orderby 中使用它时,我得到了

错误 CS1503:参数 2:无法从 'System.Linq.Expressions.LambdaExpression' 转换为 'string'

我想也许我需要在检查时使用正确的类型动态构建 Expression.Lambda,但还没有尝试过

感谢您的帮助

【问题讨论】:

标签: c# entity-framework linq expression-trees


【解决方案1】:

通过

将其转换为对象
Expression conversion = Expression.Convert(propExp, typeof(object))

返回应该没问题,但是你将不得不在另一边处理这些转换,在那里你进行 Orderby。

    private IQueryable<T> AddOrderBy<T>(IQueryable<T> query, Expression<Func<T, object>> orderByProperty, bool isAscending, bool isFirst)
{
    Expression<Func<IOrderedQueryable<int>, IQueryable<int>>> methodDef = isAscending 
        ? (isFirst ? (Expression<Func<IOrderedQueryable<int>, IQueryable<int>>>)(q => q.OrderBy(x => x)) : (Expression<Func<IOrderedQueryable<int>, IQueryable<int>>>)(q => q.ThenBy(x => x)))
        : (isFirst ? (Expression<Func<IOrderedQueryable<int>, IQueryable<int>>>)(q => q.OrderByDescending(x => x)) : (Expression<Func<IOrderedQueryable<int>, IQueryable<int>>>)(q => q.ThenByDescending(x => x)));

    // get the property type
    var propExpression = orderByProperty.Body.NodeType == ExpressionType.Convert && orderByProperty.Body.Type == typeof(object)
        ? (LambdaExpression)Expression.Lambda(((UnaryExpression)orderByProperty.Body).Operand, orderByProperty.Parameters)
        : orderByProperty;

    var methodInfo = ((MethodCallExpression)methodDef.Body).Method.GetGenericMethodDefinition().MakeGenericMethod(typeof(T), propExpression.Body.Type);
    return (IQueryable<T>)methodInfo.Invoke(null, new object[]{query, propExpression});
}

【讨论】:

  • 谢谢....想法是将字符串属性名称传递给方法。另外,它可以变成扩展方法吗?是否也可以支持 IEnumerable?
  • 如果你有一个字符串作为输入,那么你甚至不必担心转换,只需说: var param = Expression.Parameter(typeof(T)); var propExpression = Expression.Lambda(Expression.MakeMemberAccess(param, propertyName), param);然后在调用中使用它
  • 对于 IEnumerables,我猜它的代码是一样的,问题是你的数据库是否支持它???
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
  • 2021-03-20
相关资源
最近更新 更多