2017-04-18 8 views
1

Test2とTest3が正常に動作している間、Test1は "System.ArgumentException:メソッドの引数の長さの不一致"を生成します。反射を使ってイベントに登録する必要があります。単純なメソッドを使用するとすべてが機能しますが、lambdaに入ると、期待どおりに機能しなくなります。メソッドとしてlambdaをDelegate.CreateDelegateが "メソッド引数の長さの不一致"例外を生成する

すべてのlambdasのデバッグでは、「Void <> m__0(Int32)」というイベントは正しいタイプであり、「eventInfo.EventHandlerType」と同じです。

なぜ失敗するのですか?または、回避策を講じる方法は?

Test1のようにlambdaによって作成されたメソッドに引数を追加しますか?

::ここに完全なコード:

public class A 
{ 
    public void Test1() 
    { 
     var str = "aa"; 
     B.Subscribe(typeof(C), "myEvent", (int a) => { var any = str; }, null); 
    } 

    public void Test2() 
    { 
     B.Subscribe(typeof(C), "myEvent", (int a) => { var any = a; }, null); 
    } 

    public void Test3() 
    { 
     B.Subscribe<int>(typeof(C), "myEvent", callback, this); 
    } 

    public void callback(int a) { } 
} 

public static class B 
{ 
    public static void Subscribe<T>(Type type, string eventName, Action<T> callback, object target) 
    { 
     var eventInfo = type.GetEvent(eventName, BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static); 
     var handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, target, callback.Method); 
     eventInfo.AddEventHandler(null, handler); 
    } 

} 

public sealed class C 
{ 
    public static event Action<int> myEvent; 
} 

EDIT:

どうやらそれはモノのバグです。デリゲートを取得するためのGetInvocationList()[0]は上の例の問題を修正します。

ただし、イベントを購読すると、 "System.InvalidCastException:ソースタイプから宛先タイプにキャストできません。"イベントはタイプアクションのが、カスタムデリゲートでない場合:(クラス「C」はそのようであれば、それはクラス「C」は、上記のようなものであるならば、それは罰金渡し、スロー)

public sealed class C 
{ 
    public static event MyDel myEvent; 
    public delegate void MyDel(int a); 
} 

それは別の問題ですか?編集#2、イベントはMyDelタイプを想定していますが、アクションInt32を取得します。 Action<T>からMyDel以上に変換するには、どのタイプのイベントが可能かわからないので、eventInfo.EventHandlerTypeに変換するにはどうすればよいですか。

+1

MS .NETでうまく動作します。モノ問題があるかもしれませんか? – VinSmile

+0

モノのバグにバグがあるようです。これをチェックするhttp://lists.ximian.com/pipermail/mono-bugs/2010- December/126824.html –

+0

'Method'の代わりに' GetInvocationList() '(返されるリストの最初の要素)を使うとどうなりますか? ?後者はうまくいくはずですが、@ VinSmileが言っているように、Monoの問題かもしれません。 –

答えて

0

さらに詳しい調査の後、私はtargetが悪かったことに気付きました。

クラスで定義されたメソッドの場合、クラスインスタンスのターゲットは大丈夫です。 ラムダについては、ラムダが作成されたメソッドの内部で定義されたローカル変数に干渉しない限り、nullであると考えました。少なくともヌルで動作します。

のでアクションDelegate.CreateDelegatecallback.Targetを使用して問題を解決し、ターゲットプロパティを持っています。

ラムダのターゲットは、実際にクラスインスタンスとそれが接触するすべてのローカル変数への参照を保持します(デバッガはそれを示します)。

奇妙なことに、それは最新の.NETで動作しました。モノと.NETのわずかな違いかもしれません。