2016-10-27 4 views
0

eine Schnittstelle Gegeben:Wie kann ich eine EventInfo für ein Ereignis programmgesteuert abrufen, ohne den Namen hart zu codieren?

IEventProvider 
{ 
    event EventHandler<string> StringAvailable; 

    void RequestString(); 
} 

ich eine EventInfo für StringAvailable durch einige Verfahren abrufen möchten, die wie folgt aufgerufen werden kann: EventInfo ei = GetEventInfo(providerInstance.StringAvailable) oder etwas in diesem Sinne. Ich möchte keine Zeichenfolge mit dem Namen übergeben müssen.

Ich habe versucht, Lambdas und Expression-Bäume zu missbrauchen, um den Namen des Ereignisses zu extrahieren, das übergeben wurde, aber ohne Erfolg. Da Ereignisse keine erstklassigen Mitglieder in C# sind, erweist sich dies als schwierig. Ich helfe nur, einen Weg zu finden, um den Namen des Ereignisses zur Laufzeit mit Code zu erhalten, der vom Compiler statisch validiert werden kann, um sicherzustellen, dass das Ereignis zur Kompilierzeit existiert.

Meine Problemumgehung ist jetzt, alle Ereignisse aus den Klassen zu entfernen, mit denen ich arbeiten möchte, und sie in Action<T> zu ändern. Dies ist jedoch weniger als ideal.

Für diejenigen von Ihnen, die sich wundern, warum ich das tue, möchte ich zulassen, dass Klassen, die das ereignisbasierte asynchrone Muster verwenden, automatisch zur Laufzeit mit Hilfe der IL-Generierung an async/awatet angepasst werden. In meiner obigen Beispielschnittstelle würde der Adapter und StringAvailable umhüllen und public async Task<string> RequestStringAsync() unter Verwendung von DynamicMethod freilegen.

Antwort

1

schreiben Sie die Provider Instanz ein Verfahren passieren könnte welches die EventInfo (s) pro Reflektion erhält.

Hier sind drei Beispiele:

var singleEvent = GetEventInfo(providerInstance); 

public static EventInfo GetEventInfo(IEventProvider eventProvider) 
{ 
    var type = eventProvider.GetType(); 
    return type.GetEvent(nameof(eventProvider.StringAvailable)); 
} 

Dieser bekommt die Veranstaltung mit dem hartcodierte nameof-Operator.

var singleEventWithName = GetEventInfo(providerInstance, nameof(providerInstance.StringAvailable)); 

public static EventInfo GetEventInfo(IEventProvider eventProvider, string name) 
{ 
    var type = eventProvider.GetType(); 
    return type.GetEvent(name); 
} 

Hier könnten Sie den Namen mit dem Nameof-Operator übergeben.

var allEvents = GetEventInfos(providerInstance); 

public static EventInfo[] GetEventInfos(IEventProvider eventProvider) 
{ 
    return eventProvider.GetType().GetEvents(); 
} 

Und dieser gibt nur alle EventInfos des Anbieters zurück.

Ich hoffe, das hilft.

bearbeiten

Besser wäre:

var eventInfo = GetEventInfo(nameof(providerInstance.StringAvailable)); 

public static EventInfo GetEventInfo(string name) 
{ 
    return typeof(IEventProvider).GetEvent(name); 
} 
+0

Oh mein Gott ich wusste nicht, 'nameof' war eine Sache! Das ist großartig. Vielen Dank. –

1

Wenn ich Sie richtig verstehe, würde ich eine Verlängerung Methode wie diese

public static class Ext 
{ 
    public static Task<string> RequestStringAsync(this IEventProvider cls) 
    { 
     var tcs = new TaskCompletionSource<string>(); 
     EventHandler<string> handler = null; 

     handler = (o, s) => 
     { 
      tcs.SetResult(s); 
      cls.StringAvailable -= handler; 
     }; 

     cls.StringAvailable += handler; 

     cls.RequestString(); 

     return tcs.Task; 
    } 
} 

und es verwenden,

public class MyEventProvider : IEventProvider 
{ 
    public event EventHandler<string> StringAvailable; 

    public void RequestString() 
    { 
     var temp = StringAvailable; 
     if (temp != null) temp(this, "aaaaa"); 
    } 
} 

var p = new MyEventProvider(); 
var str = await p.RequestStringAsync(); 
+0

Ja, das ist ziemlich viel, was ich tun wollte, aber dynamisch zur Laufzeit. Der Grund für die Automatisierung ist, dass ich Hunderte von Ereignissen auf diese Weise anpassen muss und nicht alle von Hand schreiben möchte. –

Verwandte Themen