このクラスのインスタンスを渡せないのはなぜですか...
class Item<T> where T : Thing { }
...このメソッドに:
void DoSomething(Item<Thing> item);
に制限Item<T>
しているのでItem<Thing>
、アイテムをに送信する前にキャストしても安全DoSomething
ですが、フレームワークがこれを処理しないのはなぜですか?
クラスがあると仮定します。
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をにキャストすることはできません。Thing
Value
SomeOtherThing
Thing
Item<SomeOtherThing>
Item<Thing>
それで、あなたは何ができますか?
さて、あなたがの定義を制御するならDoSomething
、おそらくそれも一般的であるべきです。
DoSomething
このように見える場合:
void DoSomething<T>(Item<T> item)
where T : Thing
{ }
Item<SomeOtherThing>
次に、以前は問題を引き起こしていた操作が内から有効でなくなったため、を使用して呼び出すことができますDoSomething
。
想像
class Derived : Thing {}
にItem<Derived>
割り当てることはできませんItem<Thing>
。
そのようにメソッド宣言をもう少し具体的にする必要があります。
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
}
あなたが抱えている問題は、あなたのメソッドがに固有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番目は最初に適切ではありません。)したがって、出力と入力の両方としてサポートする必要がある場合、このアプローチを利用できません。Set
SomeOtherThing
Things
T