I am building a helper method that returns an expression based on a property that could be used in an orderby or where, etc. in a linq to entities operation.
I won't know the type of the property upfront, so I have declared it as object and dynamic and have also tried to use Expression.Convert
but it will not work for non string typed properties.
The current property type that is not a string that I'm working with is int?
and the error I get is
Expression of type 'System.Nullable`1[System.Int32]' cannot be used for return type 'System.Object';
Code:
var param = Expression.Parameter(typeof(Employee), "x");
MemberExpression propExp = Expression.Property(param, "somePropertyName");
Expression.Lambda<Func<Employee, object>>(propExpression, param);
AS I said, I've used object and dynamic in line above with same results. I've also tried to convert it to the right type but that doesn't work:
Expression conversion = Expression.Convert(propExp, ((PropertyInfo)propExp.Member).PropertyType)
While I'm in debug mode and I try this, Expression.Lambda(conversiona, param)
, it seems to work
{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]]"}
...but when I use it in an orderby I get
error CS1503: Argument 2: cannot convert from 'System.Linq.Expressions.LambdaExpression' to 'string'
I thought that maybe I needed to dynamically build the Expression.Lambda using the correct type as I inspect it but haven't tried that yet
Thanks for any help
Convert it to object by
Expression conversion = Expression.Convert(propExp, typeof(object))
That should be ok to be returned, but then you will have to deal with these converts on the other side, where you do the 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});
}