この記事で使用する2つの単純なクラスの定義から始めましょう。
これはまだ具体的なことは何もしていない古典的なクラス階層ですが、今は必要ありません。 ここで、ダミークラスを定義します。これは、任意の型のコンテナになります。public class Shape { } public class Circle : Shape { } * This source code was highlighted with Source Code Highlighter .
public class Shape { } public class Circle : Shape { } * This source code was highlighted with Source Code Highlighter .
public class Shape { } public class Circle : Shape { } * This source code was highlighted with Source Code Highlighter .
public class Shape { } public class Circle : Shape { } * This source code was highlighted with Source Code Highlighter .
public class Shape { } public class Circle : Shape { } * This source code was highlighted with Source Code Highlighter .
public class Shape { } public class Circle : Shape { } * This source code was highlighted with Source Code Highlighter .
public class Shape { } public class Circle : Shape { } * This source code was highlighted with Source Code Highlighter .
public class Shape { } public class Circle : Shape { } * This source code was highlighted with Source Code Highlighter .
階層とコンテナがあります。 では、C#-3.0の現在のバージョンではできないことを見てみましょう。
*このソースコードは、 ソースコードハイライターで強調表示されました。
- パブリック インターフェイス IContainer <T>
- {
- T GetItem();
- }
- パブリック クラスコンテナ<T>:IContainer <T>
- {
- プライベート Tアイテム。
- パブリックコンテナ(Tアイテム)
- {
- this .item = item;
- }
- パブリック T GetItem()
- {
- 返品アイテム;
- }
- }
戻り値の型がIContainer <Shape>として定義されているGetListメソッドがあり、Container <Circle>を返します。 CircleはShapeを継承し、ContainerはIContainerインターフェイスを実装しているため、これが機能するように見えるかもしれません。 しかし、あなたはそれを推測しました、C#3.0はこれに対応していません。
*このソースコードは、 ソースコードハイライターで強調表示されました。
- static void Main( string [] args)
- {
- IContainer <Shape> list = GetList();
- }
- public static IContainer <Shape> GetList()
- {
- 新しいコンテナ<円>( 新しい円())を返します。
- }
C#4.0では、これを機能させる方法があります-IContainerインターフェイス定義のtypeパラメーターにoutキーワードを追加するだけです(C#4.0の共分散はインターフェイスとデリゲートに制限されていることに注意してください)。
この構造は、型Tが共変であることをコンパイラーに伝えます。つまり、すべてのIContainer <T>は、Tと同等またはそれ以上の型を受け入れます。上記のように、戻り型はIContainer <Shape>でしたが、インターフェイスへの出力パラメータを使用すると、IContainer <Circle>を簡単に返すことができるので、なぜoutキーワードを使用することにしましたか? これは、型パラメーターを共変として定義すると、インターフェイスからこの型のみを返すことができるためです。 たとえば、次のような構造は許可されていません。
*このソースコードは、 ソースコードハイライターで強調表示されました。
- パブリック インターフェイス IContainer < out T>
- {
- T GetItem();
- }
しかし、なぜ機能しないのでしょうか? 答えは実際には非常に簡単です-型の安全性。 私たちがしたことの結果を見てみましょう:
*このソースコードは、 ソースコードハイライターで強調表示されました。
- パブリック インターフェイス IContainer < out T>
- {
- void SetItem(T item);
- T GetItem();
- }
Tは共変であるため、Container <Circle>をIContainer <Shape>型の変数に割り当て、さらにIContainer <Shape>型のパラメーターを受け取る静的SetItemメソッドに渡し、このパラメーターを取得して追加しようとします。タイプSquareの変数。 すべてが正しいようです-パラメータタイプはIContainer <Shape>であり、これによりSquareを追加する権利が与えられます。 間違っています。 Circleを保持するコンテナにSquareを追加しようとすると、この式は「爆発」します。 したがって、outキーワードを使用すると、共分散は一方向のみに制限されます。
*このソースコードは、 ソースコードハイライターで強調表示されました。
- static void Main( string [] args)
- {
- IContainer <Shape> container = new Container <Circle>();
- SetItem(コンテナ);
- }
- public static void SetItem(IContainer <Shape>コンテナー)
- {
- container.SetItem( new Square()); //ブーム!!!
- }
おそらく、これらすべてがCLR 4.0でどのように実装されているのか疑問に思っているでしょうか? 実装の必要はありません。 ジェネリック型はCLR 2.0で機能し、既に同様の動作を許可していました。 C#は型の安全性を維持しようとしたため、これを行うことはできませんでしたが、CLRはこれを一度に処理します。 そして、少し注意してください-C#の配列はこの動作を許可するので、試してみてください。 この記事をお楽しみいただき、このシリーズの新しい記事が間もなく登場することを願っています!
記事翻訳 C#4.0新機能パート3-汎用共分散
私の ブログ からのクロスポスト