6

私はこれらのクラスを持っています:

class Asset
{    }

class House:Asset
{    }

これらの部外者の静的関数を検討してください。

static void Foo (Asset a) { }
static void Foo (House h) { }

私が書く場合:

House h = new House (...); 
Foo(h);

それが呼び出されますFoo(House)(コンパイル時バインディング)

私が書く場合:

Asset a = new House (...);
Foo(a); 

それが呼び出されますFoo(Asset) (コンパイル時バインディング)

ゴール : ランタイム型メソッドにアクセスします :

私には2つのオプションがあります:

1)このようなダイナミックを使用:

 Asset a = new House (...);
 Foo ((dynamic)a); // NOW it will call  Foo(House)

2) 関数をstaticからoverrideusingに移動しますpolymorphism mechanism

質問:

それを行う他の方法はありますか(関数をpolymorphism mechanism||に移動せずにdynamic)?

4

3 に答える 3

9

goal : ランタイム型メソッドにアクセスする

そのためのdynamicキーワードです。実際には、複数のディスパッチを行うための非常にクリーンで高速な方法です。

複数派遣の究極の選択肢は

  1. dynamic
  2. ダブルディスパッチ仮想メソッド
  3. 一部のハッシュ化された匿名関数ルール コレクション
  4. if (x is House) ... else if(x is Asset)...
  5. リフレクション -- 本当に遅くて醜い

質問: 他の方法はありますか (関数をポリモーフィズム メカニズム || 動的に移動せずに) ?

そうですdynamic、高速で、エラーが発生しにくく、非常にクリーンな構文を使用できる場合に、多くの作業を行う方法があります。

于 2012-04-26T13:09:10.163 に答える
1

静的なエントリ ポイントが必要であるが、ポリモーフィックな動作も必要な場合、最も簡単なブレンドはシングルトン パターンを使用することです。これは静的エントリ ポイントを提供し、返されるオブジェクトにはポリモーフィック メソッドが含まれます。

また、シングルトンは恐ろしく悪いことだと言っている人を無視することをお勧めします。プリマドンナのシングルトンの悲惨な説教は、中級レベルの開発者のシボレスです。シングルトンは単なるツールです。必要に応じて使用してください。

于 2012-04-26T13:34:08.910 に答える
1

私はこれがボンネットの下で起こっていると思いますFoo((dynamic)a):

Asset a = new House();

Type t = typeof(MainClass);
t.InvokeMember("Foo", 
     System.Reflection.BindingFlags.InvokeMethod, null, 
     t, new object[] { a });

それは解決しますFoo(House h)


リフレクション (例: InvokeMember) を使用せずに monodis.exe に簡単に移動します。つまり、代わりに dynamic キーワードを使用しますAsset a = new House(); Foo((dynamic)a)。これが IL です。

IL_0025:  ldstr "Foo"
IL_002a:  ldnull 
IL_002b:  ldtoken MainClass
IL_0030:  call class [mscorlib]System.Type class [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)

「Foo」は、ダイナミクスがリフレクションのような種類のビジネスであるという死んだ景品です。

さて、これは動的ではありません。つまり、次のようになりAsset a = new House(); Foo(a)ます。

IL_0010:  ldloc.0 
IL_0011:  call void class MainClass::Foo(class Asset)

焼かれた命令はほぼ決定され、変更されず、常に解決されますFoo(Asset);

(monodis.exe または ildasm.exe を介して) 動的動作を分析するために使用できる完全なコードを次に示します。

using System;

public class MainClass {
    public static void Main() {

        Console.WriteLine("Hei");

        Asset a = new House();        
        Foo(a);    
        Foo((dynamic)a);  

        object x = 7;
        Foo((dynamic)x);
    }

    public static void Foo(House h) { Console.WriteLine("House"); }
    public static void Foo(Asset a) { Console.WriteLine("Asset"); }
    public static void Foo(int i) { Console.WriteLine("int"); }
}


public class Asset {
}

public class House : Asset {
}

出力:

Hei
Asset
House
int

これにより、Foo オーバーロード int が呼び出されます。つまり、次のようになりFoo(int i)ます。

object x = 7;
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null, 
   t, new object[] { x } ); 

これも次のようになります。

t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null, 
   t, new object[] { 8 } ); 

あなたの質問では、他にどのようなオプションを使用できますか。型指定されていないオブジェクトを受け入れるメソッドを使用できます。

public static void FooDynamic(object o) 
{
    Type t = typeof(MainClass);
    t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null, t, new object[] { o } ); 
}

呼び出す:

Asset a = new House();
FooDynamic(a); // will select Foo House overload 

int i = 7;
FooDynamic(i); // will select Foo int overload

上記のコードにこの API を使用することもできます:public static void Foo(object o)の場合、次のように Foo を呼び出す必要があります。

Asset a = new House();
Foo((object)a); // will resolve to House

C# 4 には既にdynamic機能があることを考えると、開発者がまだ C# 3 を使用していない限り、リフレクションを使用するのは難しいでしょう。そのため、代わりに動的アプローチを使用してください :-)


アップデート

このコードを実行すると、文字「B」が表示されるまでに約 2 秒のかなりの遅延がありますdynamic。ダイナミックとリフレクションのコード順序を入れ替えても、ダイナミックの遅延は再現可能です。リフレクションの遅延は感知できず、動的よりも高速です。

using System;

public class MainClass {

    public static void Main() {

        // there's a delay on initial dynamic call, about two seconds
        Test (); 
        Console.ReadLine ();

        // dynamic's speed is instant on subsequent calls, 
        // as clarified by Eric Lippert, the delegate is cached,
        // hence the elimination of delay on subsequent dynamic calls
        Test (); 

    }

    public static void Test() {

        Asset a = new House();

        Console.WriteLine("A");
        Foo((dynamic)a);  // there is a considerable delay here, the "B" string appears after two seconds

        Console.WriteLine ("B");        
        Type t = typeof(MainClass);
        t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null, t, new object[] { a } ); 

        Console.WriteLine("C");

    }


    public static void Foo(House h) { Console.WriteLine("House"); }
    public static void Foo(Asset a) { Console.WriteLine("Asset"); }
    public static void Foo(int i) { Console.WriteLine("int"); }
}


public class Asset {
}

public class House : Asset {
}
于 2012-04-26T12:49:30.663 に答える