2012-04-24 17 views
5

Nasz system UI może generować formularz z MethodInfo. Przed System.Linq.Expressions, byliśmy coraz MethodInfo użyciu odbicia (metoda 1):Zwiększenie wydajności otrzymywania MethodInfo z MethodCallExpression

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

Zła część jest to, że jeśli zmienił podpis lub nazwę InstanceMethod, kod będzie nadal skompilować.

Wprowadź wyrażenia. Teraz robimy to (metoda 2):

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

lub ten (metoda 3):

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

składnia jest "lepszy", otrzymujemy intellisense, a my się błędy kompilacji, jeśli metoda nie robi istnieje lub podpis się nie zgadza. Jednak metoda 2 i metoda 3 są około 10 do 20 razy wolniejsze od odbicia.

niektóre numery (mierzone stoper):

jednego połączenia: Metoda 1: 0,0000565 Metoda 2: 0,0004272 Metoda 3: 0,0019222

100000 połączenia: Metoda 1: .1171071 Metoda 2: 1.5648544 Metoda 3: 2.0602607

Nie kompilujemy wyrażenia ani nie wykonujemy go i jestem zainteresowany, czy ktoś ma wyjaśnienie różnicy w wydajności .

UPDATE: getMethod <> Kod:

Metoda 2:

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

Metoda 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

po prostu pytasz ... czy zamiast tego próbowałeś z niestandardowym delegatem? tj. 'new SomeDelegateType (x.Method)'? –

+0

Pokaż zawartość GetMethod. Trudno jest analizować kod, który nie jest widoczny ... – usr

+0

@MarcGravell, nie jestem pewien, czy rozumiem twoje pytanie. –

Odpowiedz

1

Domyślam się, że to wolniej, ponieważ wersje wyrażenie to samo odbicie (chociaż mogą używać skrótu IL methodof, który nie ma odpowiednika w C#) w celu utworzenia drzewek wyrażeń, dodatkowo na narzut tworzenia samych drzew dla każdego wywołania (nie sądzę, że są one buforowane przez kod, który emituje kompilator); dodatkowo musisz przeczytać te drzewa, aby odzyskać metodę.

Refleksja może być "powolna", ale w rzeczywistości jest bardzo cholernie szybka; zwłaszcza, że ​​uważam, że dane za kulisami są również buforowane. Tak więc, gdy zadzwonisz GetMethod, drugie połączenie będzie szybsze. To dostarcza kolejnego przekonującego dowodu na to, dlaczego kolejne wersje drzewek wyrażeń są wolniejsze - ponieważ faktycznie wykonują więcej pracy.

Jeśli nie masz nic przeciwko IL, skompiluj wersję ze wszystkimi trzema, a następnie przeanalizuj skompilowany obraz za pomocą ILSpy lub Reflectora (w trybie C# oba będą sprytne i ponownie zamontoją kod wyrażenia z powrotem na C#, który nie jest dobrze, więc przełącz się na tryb IL) - spójrz na kod, który emituje, aby wygenerować drzewa ekspresji, a zobaczysz, co mam na myśli.

Powiązane problemy