2015-09-21 8 views
8

Próbuję ulepszyć mój kod refleksji, tworząc opcję Delegatów dla metod Getter i Setter.Przesyłanie uczestnika do działania <T> lub Func <T> w środowisku wykonawczym

Mój kod wygląda następująco:

MyObject obj = new MyObject(); 
var prop = obj.GetType().GetProperty("Prop"); 
var getType = typeof(Func<>).MakeGenericType(prop.PropertyType); 
var setType = typeof(Action<>).MakeGenericType(prop.PropertyType); 

var getMethod = prop.GetGetMethod().CreateDelegate(getType, obj); 
var setMethod = prop.GetSetMethod().CreateDelegate(setType, obj); 

// I'd like to change this section and not to use a dynamic!! 
dynamic castedGet = Convert.ChangeType(getMethod, getType); 
dynamic castedSet = Convert.ChangeType(setMethod, setType); 

CreateDelegate zwraca Delegate i korzystania DynamicInvokenie jest wydajność mądry.

Przerzuciłem (na stałe) Delegate do Action<T> \ Func<T> i zobaczyłem ogromny wzrost mojej wydajności.

Potem próbował rzucić Delegate do Action<T> \ Func<T> w czasie pracy (przy użyciu Convert.ChangeType i dynamic) i mój występ został ranny - prawdopodobnie ze względu na fakt, że używam typ dynamic.

Jestem prawie pewny, że mogę to zrobić bez dynamic.

Chyba rozwiązanie ma coś wspólnego z expression trees, ale nie jestem pewien, jak kod coś takiego. Jeśli ktoś ma dobre rozwiązanie, które nie korzysta z numeru expression trees, to również interesujące będzie usłyszeć o nim.

+0

Czy wykonujesz cały ten kod * co * raz, czy też buforujesz gdzieś delegatów, a następnie je wywołujesz? – Dai

+0

@Dai - To jest mała część mojego kodu i rodzaj próbki. Czekam na buforowanie właściwości, gettera, setera dla każdej własności - w leniwy sposób. –

+0

Dlaczego mimo to używasz 'dynamic'? 'Convert.ChangeType' nie zwraca obiektu związanego z opóźnieniem. – Dai

Odpowiedz

3

Jeśli twoim celem jest, aby być w stanie powołać swoje działania/funkcji nie znając typ zwracany w czasie kompilacji, to prawdopodobnie chcesz skończyć z Action<object> i Func<object>, prawda?

Można to zrobić bez konieczności kompilowania drzewa wyrażenie lub cokolwiek, tak jak poniżej:

// Use reflection to create the action, invoking the method below. 
var setAction = (Action<object>) this.GetType() 
    .GetMethod("CastAction", BindingFlags.Static | BindingFlags.NonPublic) 
    .MakeGenericMethod(prop.PropertyType) 
    .Invoke(null, new object[]{setMethod}); 

// invoke the action like this: 
object value = 42; // or any value of the right type. 
setAction(value); 

Stosując tę ​​metodę pomocniczą:

private static Action<object> CastAction<T>(Delegate d) 
{ 
    var action = (Action<T>)d; 
    return obj => action((T)obj); 
} 

Moje testy pokazują, że jest to około 25% szybciej niż użycie dynamic i około 45% wolniej niż samo powiedzenie obj.Prop = 2;

+0

Jaka jest różnica między odpowiedzią @ k3b? OP powiedział, że "Używanie MethodInfo.Invoke jest dużo wolniejsze niż tworzenie delegatów i wywoływanie ich" –

+0

@codroipo: W tym przypadku używam 'MethodInfo.Invoke()' tylko po to, aby utworzyć delegata w pierwszej kolejności. To jest coś, co metoda OP "ChangeType" skutecznie robi pod kołdrą. Wynikowa akcja 'setAction' może jednak zostać wywołana znacznie szybciej niż wywołanie' setter.Invoke() ', jak to robi odpowiedź k3b. Jest nieco szybszy niż wywołanie dynamicznej akcji castedSet, ponieważ nie polega na dynamicznym wywołaniu. – StriplingWarrior

+1

@StriplingWarrior - To bardzo interesujące. Testy porównawcze są lepsze niż użycie dynamicznego i wolniejszego niż w przypadku zakodowanego na stałe kodowania. Obecnie jest to najszybszy ogólny sposób, jaki mam. Dziękuję za Twoją odpowiedź. Czekam na więcej odpowiedzi i zaakceptuję, jeśli nie będzie nic lepszego. Dzięki!!!! +1. –

1

Czy istnieje powód, dla którego musisz użyć działania < T> lub Func < T>, aby dynamicznie uzyskać/ustawić propery?

Jeśli nie można użyć PropertyInfo.GetMethod() i SetMethod()

MyObject obj = new MyObject(); 
PropertyInfo prop = obj.GetType().GetProperty("Prop"); 

MethodInfo getter = prop.GetMethod(); 
getter.Invoke(...) 

MethodInfo setter = prop.SetMethod(); 
setter.Invoke(...) 
+0

Powodem jest wydajność. Używanie MethodInfo.Invoke jest dużo wolniejsze niż tworzenie delegatów i wywoływanie ich (zakładam, że chcę je buforować). Dzięki i tak. –

+1

Nie byłem świadomy (i nigdy nie myślałem i nigdy nie sprawdzałem siebie), że 'Invoke()' jest wolniejszy niż ducktyping używając 'dynamic' – k3b

Powiązane problemy