2016-11-12 5 views
1

Я создаю вспомогательный метод, который возвращает выражение, основанное на свойстве, которое может использоваться в orderby или где и т. Д. В операции linq для сущностей.Невозможно построить lambda Выражение с неизвестным типом свойства

Я не буду знать тип свойства upfront, поэтому я объявил его как объект и динамический, а также попытался использовать 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); 

Как я уже сказал, я использовал объект и динамика в строке выше с теми же результатами. Я также попытался преобразовать его в правильный тип, но это не работает:

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» в «строка»

Я подумал, что, может быть, мне нужно динамически строить Expression.Lambda с помощью правильного типа, как я проверить его, но не пробовал, что еще

Спасибо за любую помощь

+2

Вместо того, чтобы пытаться построить выражение, попробуйте создать целую 'OrderBy (Descending)'/'ThenBy (Descending)' call. В противном случае у вас будет такая же проблема, как в [Как указать тип предиката, который я не буду знать до выполнения?] (Http://stackoverflow.com/questions/40544393/how-can-i-specify- a-predicates-type-which-i-wont-know-until-runtime/40545008 # comment68329807_40545008) –

+0

Возможный дубликат [Как использовать строку для создания EF-заказа по выражению?] (http://stackoverflow.com/ Вопросы/39908403/how-to-use-a-string-to-create-a-ef-order-by-expression) –

ответ

1

Преобразовать его объектные

Expression conversion = Expression.Convert(propExp, typeof(object)) 

Это должно быть хорошо, если вы вернетесь, но тогда вам придется иметь дело с этими конвертерами с другой стороны, где вы делаете заказ.

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

Спасибо .... идея заключалась в том, чтобы передать в имя свойства string метод. Кроме того, может ли он быть превращен в метод расширения? Можно ли также поддерживать IEnumerable? – ManOfSteele

+0

Если у вас есть строка в качестве входных данных, тогда вам даже не нужно беспокоиться об конвертации, просто скажите: var param = Expression.Parameter (typeof (T)); var propExpression = Expression.Lambda (Выражение.MakeMemberAccess (param, propertyName), param); , а затем использовать это в вызове – MBoros

+0

Для IEnumerables, я думаю, это тот же код, вопрос в том, поддерживает ли ваш db ??? – MBoros