2009-03-05 8 views
2

私は、デリゲートとカスタムイベントargsを使用してカスタムイベントを定義するクラスを持つアセンブリを持っています。今度は、このアセンブリを自分のコードから動的にロードし、このクラスのインスタンスを作成する必要があります。ここまで私は大丈夫です。今度は、カスタムデリゲートを使用してクラスオブジェクトによって生成されたイベントにイベントハンドラを提供する必要があります。 Relectionを使用してクラスから発生したイベントにイベントハンドラを追加するにはどうすればよいですか?C#Delgatesとイベント

答えて

0

私はそれを以前にしなければなりませんでしたが、本当に苦痛でした - このtutorialを最終的に見つけました。

反射でイベントを接続するために使用できるインターフェイスを別のアセンブリに含めることは可能でしょうか?ちょうど考え...

1

イベントはマルチキャストのデリゲートです。このイベントをSystem.Delegateの型として取得するには、Delegate.Combineを使用して2つのインスタンスを結合し、デリゲートを結合されたデリゲートに設定します。

C#は、このための素晴らしい速記構文は次のとおりです。

class SomeClass 
{ 
    public event Action<string> TextEvent; 
} 

あなたはこのような何か書きます(私は少し怠惰な感じだし、これをチェックしませんが、あなたがねじれをうまくする必要がありますここでは、自分自身)

var obj = // instance of SomeClass... 
var t = typeof(SomeClass); // you need the type object 
var member = t.GetEvent("TextEvent"); 
member.AddEventHandler(obj, new Action<string>(delegate(string s)){}); // done! 
+0

これは機能しません。イベントは、プロパティがフィールドであるのと同じくらいのフィールドです。イベントにはadd_メソッドとremove_メソッドがあります(add/removeを使用する場合を除き、プロパティget/setと同様に定義します)。 –

+0

私は答えを改訂しましたが、それは必ず動作します。 –

3

はそれを行うためのコードは次のとおりです。

class Program 
    { 
    static void Main(string[] args) 
    { 
     // Create publisher. 
     var pub = Activator.CreateInstance(typeof(Publisher)); 
     // Get the event. 
     var addEvent = typeof(Publisher).GetEvent("Event"); 

     // Create subscriber. 
     var sub = Activator.CreateInstance(typeof(Subscriber)); 
     // Get the method. 
     var handler = typeof(Subscriber).GetMethod("Handle"); 
     // Create a valid delegate for it. 
     var handlerDelegate = MakeEventHandlerDelegate(handler, sub); 

     // Add the event. 
     addEvent.AddEventHandler(pub, handlerDelegate); 

     // Call the raise method. 
     var raise = typeof(Publisher).GetMethod("Raise"); 
     raise.Invoke(pub, new object[] { "Test Value" }); 
     Console.ReadLine(); 
    } 

    static Delegate MakeEventHandlerDelegate(MethodInfo methodInfo, object target) 
    { 
     ParameterInfo[] info = methodInfo.GetParameters(); 
     if (info.Length != 2) 
     throw new ArgumentOutOfRangeException("methodInfo"); 
     if (!typeof(EventArgs).IsAssignableFrom(info[1].ParameterType)) 
     throw new ArgumentOutOfRangeException("methodInfo"); 
     if (info[0].ParameterType != typeof(object)) 
     throw new ArgumentOutOfRangeException("methodInfo"); 

     return Delegate.CreateDelegate(typeof(EventHandler<>).MakeGenericType(info[1].ParameterType), target, methodInfo); 
    } 
    } 

    class Args : EventArgs 
    { 
    public string Value { get; set; } 
    } 

    class Publisher 
    { 
    public event EventHandler<Args> Event; 

    public void Raise(string value) 
    { 
     if (Event != null) 
     { 
     Args a = new Args { Value = value }; 
     Event(this, a); 
     } 
    } 
    } 

    class Subscriber 
    { 
    public void Handle(object sender, Args args) 
    { 
     Console.WriteLine("Handle called with {0}.", args.Value); 
    } 
    } 
0

私はおそらく何かが欠けていますが、あなたが名前aを知っていればフックアップする必要があるイベントの署名を入力すると、そのイベントを公開するタイプが分かっている可能性があります。その場合、なぜ反射を使用する必要がありますか?正しくタイプされた参照がある限り、通常の方法でハンドラーをアタッチすることができます。