2012-06-18 74 views
0

我想加快反思 - >SetValue與LINQ表達式。如何使用LINQ從類型對象創建lambda表達式?

我的問題是這樣的方法:

public void SetValue<T>(T obj) 
{ 
    FieldInfo field = typeof(T).GetField("Title", BindingFlags.Instance | 
                BindingFlags.Public | 
                BindingFlags.IgnoreCase); 

    ParameterExpression targetExp = Expression.Parameter(typeof(T), "target"); 
    ParameterExpression valueExp = Expression.Parameter(field.FieldType, "value"); 

    // Expression.Property can be used here as well 
    MemberExpression fieldExp = Expression.Field(targetExp, field); 
    BinaryExpression assignExp = Expression.Assign(fieldExp, valueExp); 

    var setter = Expression.Lambda<Action<T, string>>(assignExp, targetExp, valueExp).Compile(); 

    setter(obj, "Hello World"); 

    //Console.WriteLine(obj.title); 
} 

我稱之爲是這樣的:

​​

的問題是這一行:

var setter = Expression.Lambda<Action<T, string>>(assignExp, targetExp, valueExp).Compile(); 

由於操作使用泛型,我不能用field.FieldType替換字符串...

有沒有可能做到這一點,而不必做出switch(field.FieldType)聲明,併爲每種可能的類型添加一個通用方法,這會吸引大量時間?

+2

編譯動態方法比使用反射慢,如果你每次都做。我認爲你需要緩存setter。 – usr

+0

@usr:的確如此,但我可能擔心稍後將其緩存。現在我需要先創建它。 –

回答

1

也許會需要像這樣

action = FormAction(fieldInfo); 
action(obj,valueToSet); 

當然緩存在字典中的行動。

static Action<object, object> FormAction(FieldInfo fieldInfo) 
{ 
    ParameterExpression obj = Expression.Parameter(typeof(object), fieldInfo.Name); 
    ParameterExpression value = Expression.Parameter(typeof(object)); 

    MemberExpression fieldExp = Expression.Field(Expression.Convert(obj, fieldInfo.DeclaringType), fieldInfo.Name); 
    BinaryExpression assignExp = Expression.Assign(fieldExp, Expression.Convert(value, fieldInfo.FieldType)); 

    return Expression.Lambda<Action<object, object>>(assignExp, obj, value).Compile(); 
} 
+0

我試過了,但錯過了Expression.Convert。很好,作品 - 謝謝! –

+1

你也可以看看[Fasterflect](http://fasterflect.codeplex.com/) –

0

使參數ob類型的對象,並在內部使lambda轉換爲正確的字段類型。

或者,在運行時動態構造委託類型(Action)。

或者,你可以定義的SetValue如下:

SetValue<TObject, TProperty> 

這將使這種方法一般,在物業類型。

編輯:這聽起來像選項1是最適合你的。您需要將參數類型更改爲typeof(object),並添加投:

valueExp = Expression.Convert(valueExp, field.FieldType) 

而且你需要使用Action<T, object>作爲委託類型。

+0

我知道。但是,如何!至於SetValue:那麼我會再次在編譯時需要字段/屬性類型,這是我不能擁有的,因爲每個字段的類型都不相同。同樣的問題,只是沒有Lambda表達式。 –

+0

好的,我添加了一些說明。這確實是全部。 – usr