2016-02-11 4 views
2

Я хочу, чтобы динамическое создание выражения, которое по сути является селектором свойств.Динамическое создание выражения, которое выбирает свойство объектов

Я пытаюсь использовать это, чтобы я мог предоставить гибкий пользовательский интерфейс поиска, а затем перевести выбранные параметры поиска в запрос Entity Framework.

У меня есть большая часть того, что мне нужно, благодаря другой библиотеке, которую я использую, но мне не хватает финальной части, которая переводит параметры строки запроса в соответствующий селектор выражений, который требуется другой библиотеке.

Библиотека принимает аргумент:

Expression<Func<TObject, TPropertyType>> 

Пример того, как это будет кодироваться, если запеченные в приложение будет:

Expression<Func<MyObject, int>> expression = x=> x.IntegerProperty; 

Однако, мне нужно, чтобы иметь возможность генерировать это выражение динамически, поскольку важным моментом является то, что все, что я буду знать, это тип объекта (MyObject) и имя свойства как строковое значение («IntegerProperty»). Значение свойства, очевидно, будет отображено на свойство объекта, которое может быть любого не сложного типа.

Так что, по-моему, я хочу найти способ динамически выражать выражение, которое указывает правильное свойство объекта для возврата и где возвращаемое значение определяется этим типом свойства.

код псевдо:

string ObjectPropertyName 
Type ObjectType 
Type ObjectPropertyType = typeof(ObjectType).GetProperty(ObjectPropertyName).Property 

Expression<Func<[ObjectType], [ObjectPropertyType]>> expression = x=> x.[ObjectPropertyName]; 

Update:

я дошел до этого

ParameterExpression objectParameter = Expression.Parameter(type, "x"); 
MemberExpression objectProperty = Expression.Property(objectParameter, "PropertyNameString"); 
Expression<Func<ObjectType, int>> expression = Expression.Lambda<Func<ObjectType, int>>(objectProperty, objectParameter); 

Но проблема у меня с этим является то, что тип возвращаемого значения не всегда является int, но может быть и другим типом.

+0

У вас есть 'ObjectType' как параметр' Type' или общий тип? Как вы собираетесь называть правильную версию метода в библиотеке? –

+0

У вас есть класс ExpressionBuilder для таких вещей, но я думаю, что может быть более простой способ решить вашу проблему. Какая библиотека является «другой библиотекой» и какой метод вы вызываете в каком классе? – Tewr

+0

У меня есть ObjectType в качестве типичного параметра типа – Kramer00

ответ

0

Если у вас есть и ObjectType и ObjectPropertyType в качестве параметров универсального типа, вы можете использовать Expression класс, чтобы сделать что-то вроде этого:

public static Expression<Func<TObject, TPropertyType>> Generate<TObject, TPropertyType>(
    string property_name) 
{ 
    var parameter = Expression.Parameter(typeof (TObject)); 

    return Expression.Lambda<Func<TObject, TPropertyType>>(
     Expression.Property(parameter, property_name), parameter); 
} 
+0

Спасибо. Я думаю, что вы указали мою проблему для меня, поскольку у меня нет ObjectPropertyType в качестве параметра общего типа. я бы определить ObjectTypeProperty из объекта типа, как показано ниже: Тип ObjectPropertyType = TypeOf (ObjectType) .GetProperty (ObjectPropertyName) .Property Свойство – Kramer00

+0

Если есть у '' ObjectPropertyType как 'type', то вам нужно использовать отражение для вызова метода в библиотеке классов, который у вас есть. Можете ли вы предоставить полную подпись метода в библиотеке классов? –

+0

@ Kramer00 Я предоставил вам подробную информацию о том, как вы можете это сделать, потому что это может быть сделано только через отражение. проверьте мой ответ. – vendettamit

0

Существует старая библиотека DynamicLinq интересной. Может быть, это будет полезно для вас. Он расширяет System.Linq.Dynamic для поддержки выполнения лямбда-выражений, определенных в строке. При использовании DynamicLinq вы можете сделать somethink как:

public class IndexViewModel 
    { 
     public bool HasPassword { get; set; } 
     public string PhoneNumber { get; set; } 
     public bool TwoFactor { get; set; } 
     public bool BrowserRemembered { get; set; } 
    } 

    //........... 

    Expression<Func<IndexViewModel, bool>> ex = 
    System.Linq.Dynamic.DynamicExpression.ParseLambda<IndexViewModel, bool>("TwoFactor"); 
     var model = new ReactJs.NET.Models.IndexViewModel() { TwoFactor = true }; 
     var res = ex.Compile()(model); 
     // res == true 
     System.Diagnostics.Debug.Assert(res); 
1

Как я уже говорил в комментариях, к выражению, не зная тип недвижимости легко (даже с поддержкой вложенной собственности):

static LambdaExpression MakeSelector(Type objectType, string path) 
{ 
    var item = Expression.Parameter(objectType, "item"); 
    var body = path.Split('.').Aggregate((Expression)item, Expression.PropertyOrField); 
    return Expression.Lambda(body, item); 
} 

Но тогда вам нужно найти способ вызова своего общего метода библиотеки - с помощью отражения или динамического вызова.

2

Выполнение того, что вы попросили, является сложным, но не невозможным. Поскольку тип свойства неизвестен до времени выполнения, поэтому вы не можете объявить Expression<Func<,>>, поэтому это будет сделано путем отражения.

public static class QueryableExtension 
{ 
    public static object Build<Tobject>(this Tobject source, string propertyName) 
    { 
     var propInfo = typeof(Tobject).GetProperty(propertyName); 

     var parameter = Expression.Parameter(typeof(Tobject), "x"); 

     var property = Expression.Property(parameter, propInfo); 

     var delegateType = typeof(Func<,>) 
          .MakeGenericType(typeof(Tobject), propInfo.PropertyType); 

     var lambda = GetExpressionLambdaMethod() 
         .MakeGenericMethod(delegateType) 
         .Invoke(null, new object[] { property, new[] { parameter } }); 

     return lambda; 
    } 

    public static MethodInfo GetExpressionLambdaMethod() 
    { 
     return typeof(Expression) 
        .GetMethods() 
        .Where(m => m.Name == "Lambda") 
        .Select(m => new 
        { 
         Method = m, 
         Params = m.GetParameters(), 
         Args = m.GetGenericArguments() 
        }) 
        .Where(x => x.Params.Length == 2 
           && x.Args.Length == 1 
           ) 
        .Select(x => x.Method) 
        .First(); 
    } 
} 

Использование -

var expression = testObject.Build("YourPropertyName"); 

Теперь это будет строить Expression вы желаемого с возвращаемым типом собственности. Но поскольку мы не знаем о вашей библиотеке, но я предлагаю вам вызвать ваш библиотечный метод через отражение и передать выражение, завернутое в объект.

Смежные вопросы