2

SOで次の質問を読んだ後、デリゲートの分散を掘り下げていました:Delegate.CreateDelegate()とジェネリックス:ターゲットメソッドへのバインドエラー

https://www.blogger.com/comment.g?blogID=8184237816669520763&postID=2109708553230166434でBarrykellyから非常に優れたコードを見つけました 。

ここにあります(砂糖漬けの形で:-)

using System;

namespace ConsoleApplication4
{
    internal class Base
    {
    }

    internal class Derived : Base
    {
    }

    internal delegate void baseClassDelegate(Base b);

    internal delegate void derivedClassDelegate(Derived d);


    internal class App
    {
        private static void Foo1(Base b)
        {
            Console.WriteLine("Foo 1");
        }

        private static void Foo2(Derived b)
        {
            Console.WriteLine("Foo 2");
        }

        private static T CastDelegate<T>(Delegate src)
            where T : class
        {
            return (T) (object) Delegate.CreateDelegate(
                                    typeof (T),
                                    src.Target,
                                    src.Method,
                                    true); // throw on fail
        }

        private static void Main()
        {
            baseClassDelegate a = Foo1; // works fine

            derivedClassDelegate b = Foo2; // works fine

            b = a.Invoke; // the easy way to assign delegate using variance, adds layer of indirection though

            b(new Derived());

            b = CastDelegate<derivedClassDelegate>(a); // the hard way, avoids indirection

            b(new Derived());
        }
    }
}

この1行(非常に単純に見える)を除いて、すべてを理解しています。

b = a.Invoke; //分散を使用してデリゲートを割り当てる簡単な方法ですが、間接参照のレイヤーを追加します

誰か教えてもらえますか:

  1. 静的関数に必要なパラメータを渡さずにinvokeを呼び出すことができる方法。
  2. invokeの呼び出しからの戻り値を割り当てるときに内部で何が起こっているか
  3. バリーは余分な間接参照とはどういう意味ですか(彼のコメントで)
4

1 に答える 1

9

彼は呼び出していませんInvoke( がないことに注意してください())。暗黙のデリゲート作成を使用して、 のメソッドを指すb新しいインスタンスに等しい値を設定しています。追加の間接化は、 が呼び出されたときに、 だけではなく を呼び出すことです。derivedClassDelegateInvokeaba.Invoke(new Derived())a(new Derived())

実際に起こっていることをより明確にするには:

baseClassDelegate a = Foo1; // works fine 

derivedClassDelegate b = Foo2; // works fine 

b = new derivedClassDelegate(a.Invoke); // the easy way to assign delegate using variance, adds layer of indirection though 

b(new Derived());

b = CastDelegate<derivedClassDelegate>(a); // the hard way, avoids indirection 

b(new Derived());

への最初の呼び出しは、次bのようなチェーンになります (簡単にするためにパラメーターを省略しています)。

b() -> a.Invoke() -> Foo1()

2 番目の呼び出しのb結果は次のようになります。

b() -> Foo1()

でも

これは、ある署名の委任が別の (より制限の少ない) 署名の委任を呼び出す必要がある場合にのみ必要です。彼の例では、設定するだけb = Foo1でコンパイルできますが、それでは要点がわかりません。

于 2010-05-05T16:44:55.390 に答える