2012-04-24 84 views
5

我們的UI系統可以從MethodInfo生成一個表單。 System.Linq.Expressions之前,我們使用反射獲取MethodInfo的(方法1):提高從MethodCallExpression獲取MethodInfo的性能

MethodInfo info = typeof(ExtensionTestClass).GetMethod("InstanceMethod", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(string) }, null); 

這個壞的部分是,如果我們改變InstanceMethod的簽名或名稱,代碼仍然編譯。

輸入表達式。現在我們做這個(方法2):

MethodInfo info = GetMethod<ExtensionTestClass>(x => x.InstanceMethod("defaultValue", "defaultValue")); 

或本(方法3):

MethodInfo info = GetMethod<ExtensionTestClass, string, string>(x => x.InstanceMethod); 

的語法是「更好」,我們得到智能感知,我們得到編譯錯誤,如果該方法沒有按不存在或簽名不匹配。但是,方法2和方法3比反射慢大約10至20倍。

一些數字(用秒錶測定):

單一呼叫: 方法1:0.0000565 方法2:0.0004272 方法3:0.0019222

100000呼叫: 方法1:0.1171071方法2:1.5648544 方法3:2.0602607

我們實際上不會編譯表達式或執行它,如果有人對性能差異有解釋,我很感興趣。

UPDATE:實現getMethod <>代碼:

方法2:

public static MethodInfo GetMethod<T>(Expression<Action<T>> target) 
{ 
    MethodCallExpression exp = target.Body as MethodCallExpression; 
    if (exp != null) 
    { 
     return exp.Method; 
    } 
    return null; 
} 

方法3:

public static MethodInfo GetMethod<T, A1, A2>(Expression<Func<T, Action<A1, A2>>> expression) 
{ 
    var lambdaExpression = (LambdaExpression)expression; 
    var unaryExpression = (UnaryExpression)lambdaExpression.Body; 
    var methodCallExpression = (MethodCallExpression)unaryExpression.Operand; 
    var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last(); 
    return (MethodInfo)methodInfoExpression.Value; 
} 
+2

只是問...你有沒有嘗試過使用自定義委託?即'新SomeDelegateType(x.Method)'? – 2012-04-24 21:50:00

+0

請顯示GetMethod的內容。很難分析不可見的代碼... – usr 2012-04-24 21:54:12

+0

@MarcGravell,不知道我理解你的問題。 – 2012-04-24 22:30:18

回答

1

我的猜測是,它是較慢的,因爲表達式版本做相同的反射(儘管它們可能使用IL快捷鍵methodof,它在C#中沒有模擬),以創建表達樹,除了之外,還有爲每次調用創建樹本身的開銷(我不認爲它們由編譯器發出的代碼緩存);再加上你必須閱讀這些樹才能讓方法恢復。

反射可能會「緩慢」,但實際上它很快就會變得很快;特別是因爲我相信幕後的數據也會被緩存。因此,一旦您撥打GetMethod,第二個電話會更快。這爲後續表達式樹版本爲什麼會變慢提供了另一個令人信服的證據 - 因爲它們實際上在做更多的工作。

如果你對IL感到滿意,可以用這三個版本編譯一個版本,然後使用ILSpy或Reflector分析編譯後的圖像(在C#模式下,兩者都會很聰明,並將表達式代碼重新構建回C#,這是不好;所以切換到IL模式) - 看看發出的代碼來生成表達式樹,你會明白我的意思。