2012-10-22 12 views
5

załóżmy, że jest to metoda, która trwa zmienną liczbę argumentów:Jak stworzyć delegata do celu ze zmienną liczbą argumentów

void Target(params object[] args); 

Aby dołączyć to do działania z konkretną listą parametrów tylko możemy utwórz wyrażenie lambda:

Action<int, int> someAction += (a, b) => Target(a, b); 

Czy istnieje możliwość dynamicznego utworzenia tego wyrażenia lambda, aby móc dołączyć handler do dowolnego typu zdarzenia? Coś jak:

someAction += CreateDelegate(typeof(someAction), Target); 

Próbowałem użyć Delegate.CreateDelegate ale oczekuje, że cel dostarczenie sposobu z betonu listy argumentów. Mam wrażenie, że powinno być możliwe z Expression.Lambda, ale na razie nie miałem żadnego sukcesu. Masz pomysł?

Edit

przemianowany na imprezę do działania i obsługi do celu.

+1

Zdarzenia powinny oczywiście mieć dokładnie 2 parametry : nadawca i argumenty. –

+0

@Henk Holterman INHO events może być także Akcje. Możliwe jest przekazywanie argumentów bezpośrednio i nie ma potrzeby pakowania ich w obiekt EventArgs. I jak często używasz obiektu nadawcy w programie obsługi? –

Odpowiedz

3

Wziąłem spojrzeć na wyrażeniach za lambda analizując następujący wiersz:

Expression<Action<int, int>> ex = (a, b) => Target(a, b); 

Na tej podstawie stworzyłem własną fabrykę Delegat:

public static Delegate CreateDelegate(Type delegateType, Action<object[]> target) 
{ 
    var sourceParameters = delegateType.GetMethod("Invoke").GetParameters(); 

    var parameters = sourceParameters.Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray(); 

    var castParameters = parameters.Select(p => Expression.TypeAs(p, typeof(object))).ToArray(); 

    var createArray = Expression.NewArrayInit(typeof(object), castParameters); 

    var invokeTarget = Expression.Invoke(Expression.Constant(target), createArray); 

    var lambdaExpression = Expression.Lambda(delegateType, invokeTarget, parameters); 

    return lambdaExpression.Compile(); 
} 
+1

To jest świetne! Dzięki. –

5

Delegat dla tej metody:

void Handle(params object[] args); 

Byłoby Action<object[]>, jako delegaci nie mogą korzystać z modyfikatora params. Będziesz musiał zrobić to, co robi kompilator, i zamapować inną metodę na tablicę obiektów.

Słowo kluczowe params jest obsługiwane przez kompilator, więc środowisko wykonawcze będzie używać tej metody tak, jakby po prostu pobierała normalną tablicę obiektów. Aby to zrobić, musisz zbudować tablicę obiektów z odpowiedniej listy, wypełnić ją swoimi obiektami, a następnie dołączyć metodę, która to zrobi do programu obsługi.

+3

Nie do końca - 'Action ' nie ma modyfikatora 'params', więc nie możesz go nazwać' action (foo, bar, baz) 'podczas gdy delegat, który * naprawdę * miał ten podpis *, byłby * wesprzeć w ten sposób. –

+0

Dziękujemy za szybką odpowiedź! Nadal istnieje problem z mapowaniem akcji 'Action ' na dowolne inne 'Akcja <-coś-coś'. Muszę to zrobić dynamicznie. Może za pośrednictwem Reflection? –

+0

@JonSkeet Edytowałem tak, aby było bardziej jednoznaczne, ale to było w pewnym sensie - delegaci nie mogą używać modyfikatora 'params', więc OP musiałby owijać wywołanie metody do tablicy obiektów, tak jak w jej metodzie wywołania. –

Powiązane problemy