2

この種のことについてはすでにスタックオーバーフローにいくつかの投稿がありますが、まったく同じではありません-したがって、これがすでに回答されているものである場合は、事前にお詫び申し上げます。

なぜこれが機能しないのですか?

public class MyBase { }

public class MyUtils
{
    public bool Foo<T> (T myObject) { return true; }
    public bool Foo (MyBase myBaseObject) { return false; }

    public void Go<T> (IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            // this test fails
            Assert.IsFalse (Foo (item));
        }
    }
}

上記のGo()を呼び出して、MyBaseオブジェクトのロードを渡すと、Fooを呼び出すたびに汎用のFoo()が呼び出され、trueが返されます。

new MyUtils ().Go (new MyBase[] { new MyBase (), new MyBase () });      

代わりに、専用のMyBaseバージョンを呼び出さないのはなぜですか?Foo(new MyBase())を直接呼び出すと、どの呼び出しを行うかが正しく推測されます。これは、C#3のコレクションの共分散が不足しているためですか、それとも私は愚かでこれを正しく行っていないのですか?

ありがとう!

アイザック

4

2 に答える 2

1

コンパイラは、実行時ではなくGo、プログラム(この場合は関数)のコンパイル時に呼び出すメソッドを選択するため、「特殊な」メソッドは呼び出されません。

コンパイラが関数をコンパイルしているとき、コンパイラがGo持っている唯一の情報は、タイプのオブジェクトがあるということですT。後でタイプのオブジェクトを提供できるかどうかはわかりませんMyBase。それが持っている唯一のオプションはFoo<T>オーバーロードを選択することです、そしてそれでそれはコンパイルされたプログラムにそれを焼き込みます。

アプリケーションが実行時にオーバーロードを選択し、アプリケーションの実行中にオブジェクトを見て最適なオーバーロードを選択する場合、これは「動的ディスパッチ」と呼ばれ、Ruby、Python、PHPなどの動的言語でのみ使用されます。 、など。

C#3は完全に静的であり、これをサポートしていません。このように機能させたい場合は、タイプをチェックするためにコードにifステートメントを記述する必要があります。一方、C#4は動的にサポートされています。このコードをC#4で記述している場合は、次のように「Go」関数を宣言できます。

 public void Go<T> (IEnumerable<dynamic> items)

次に、実行時に動的ディスパッチを使用して、呼び出されるオーバーロードを選択し、実行に特化したオーバーロードを呼び出します。MyBase

于 2009-12-06T00:20:30.227 に答える