1

このクラスのインスタンスを渡せないのはなぜですか...

class Item<T> where T : Thing { }

...このメソッドに:

void DoSomething(Item<Thing> item);

に制限Item<T>しているのでItem<Thing>、アイテムをに送信する前にキャストしても安全DoSomethingですが、フレームワークがこれを処理しないのはなぜですか?

4

4 に答える 4

2

クラスがあると仮定します。

public class SomeOtherThing : Thing { }

にキャストすることはItem<SomeOtherThing>できませんItem<Thing>。それらは同じではありません。

少しの間、アイテムが次のようになっていると仮定しましょう。

public class Item<T>
{
    public T Value { get; set; }
}

DoSomething次に、次のようなことを行う可能性があります。

void DoSomething(Item<Thing> item)
{
    item.Value = new Thing();
}

にを渡すと、Item<SomeOtherThing>に新しいをDoSomething割り当てたばかりですが、値がタイプのプロパティである場合、オブジェクトをそれに設定することはできません。これは型システムを壊していたでしょう。コンパイラは、これがオプションであることを認識しています。このため(および同じ基本的な問題を抱えている他の多くの操作)、aをにキャストすることはできません。ThingValueSomeOtherThingThingItem<SomeOtherThing>Item<Thing>

それで、あなたは何ができますか?

さて、あなたがの定義を制御するならDoSomething、おそらくそれも一般的であるべきです。

DoSomethingこのように見える場合:

void DoSomething<T>(Item<T> item)
    where T : Thing
{    }

Item<SomeOtherThing>次に、以前は問題を引き起こしていた操作が内から有効でなくなったため、を使用して呼び出すことができますDoSomething

于 2013-02-18T19:13:17.400 に答える
1

想像

class Derived : Thing {}

Item<Derived>割り当てることはできませんItem<Thing>

于 2013-02-18T18:48:21.763 に答える
1

そのようにメソッド宣言をもう少し具体的にする必要があります。

void DoSomething<T>(Item<T> item)
    where T : Thing
{
    // now your method knows that T must be of time Thing and you can use it
}
于 2013-02-18T18:56:24.287 に答える
1

あなたが抱えている問題は、あなたのメソッドがに固有Item<Thing>Item<Something>あり、有効な引数ではないということです。C#はジェネリッククラスの共分散をサポートしていません。いくつかのオプションがあります。

「最も簡単な」方法は、メソッドを汎用化し、Thingに制約を追加することです。これが最初にアドバイスされるアプローチです。

void DoSomething<T>(Item<T> item) where T : Thing
{
}

Thingこれにより、すべてのサブクラスに対応できるメソッドを使用しながら、必要に応じてのすべてのメンバーにアクセスできるようになります。

より多くの制限がある別のオプションは、それに対する非ジェネリックベースをItem<Thing>単純に持つことですItem。(その中で、以前にTを公開していた場所ならどこでも、公開しobjectます。考えてみてくださいIEnumerable<T>:: IEnumerable。)

void DoSomething(Item item)
{
}

あなたの方法は単に期待するでしょう、Itemそしてあなたはそれで働くことができます。ただし、特定の要件があるThing場合は、もう少しデリケートです。必要に応じてキャストする必要がありますが、TがThingである場所ではないインスタンスを誰かが渡す可能性もあります。Item<T>

もう1つのオプションは、メソッドのシグネチャをそのままにして、クラスからインターフェイスに変換することです。これにより、共分散を使用できます。(共変性/反変性は、インターフェイスおよびデリゲートタイプの.NET 4.0でサポートされています。)

interface Item<out T> 
{
    T Get();
    // void Set(T foo); // invalid  
}

ここでも、1)タイプを(明らかに)変更する必要がありますが、2)T出力位置でのみ公開するように制限されるという問題があります。Get()メソッドがサポートされていることに注意してください。は入力であるSet(T)ため、メソッドはそうではありませんT。これにより、インターフェイスが共変的に有効になりません。(を渡して、メソッドが。を呼び出そうとしていると想像してくださいItem<Something>。どちらもですが、明らかに2番目は最初に適切ではありません。)したがって、出力入力の両方としてサポートする必要がある場合、このアプローチを利用できません。SetSomeOtherThingThingsT

于 2013-02-18T19:19:02.893 に答える