2016-02-11 118 views
2

我希望能夠動態地構建表達式,它本質上是一個屬性選擇器。動態創建一個選擇對象屬性的表達式

我想使用這個,所以我可以提供一個靈活的搜索用戶界面,然後將選定的搜索參數轉換爲實體框架查詢。

我有大部分需要感謝我使用的另一個庫,但缺少將我的查詢字符串參數轉換爲其他庫所需的適當表達式選擇器的最後部分。

庫中取得的參數:

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]; 

更新:

我已經得到儘可能這

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

如果你有兩個ObjectTypeObjectPropertyType作爲泛型類型參數,你可以使用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運算(對象類型).GetProperty(ObjectPropertyName).Property – Kramer00

+0

如果有有''ObjectPropertyType作爲'Type',則需要使用反射調用你擁有的類庫中的方法。你能提供類庫中方法的完整簽名嗎? –

+0

@ Kramer00我爲您提供了詳細信息和實施方法,因爲它只能通過反射完成。檢查我的答案。 – vendettamit

0

有老intresting庫DynamicLinq。可能會對你有用。它擴展了System.Linq.Dynamic以支持在字符串中定義的Lambda表達式的執行。隨着使用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"); 

現在,這將建立你的財產返回類型所需的表達。但由於我們不知道你的庫,但我建議你通過反射調用你的庫方法,並傳遞包裝在對象下的表達式。