2011-02-02 14 views
1

ここではStackOverflowのcovariance and contravarianceにいくつかの素晴らしいリソースがありますが、私はcontravarianceの基本を誤解しているようです。クラスの暗黙の反差異 - 簡単に失敗した例

public partial class WebForm1 : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     A a = new B(); 
     B b = new A(); 
    } 
} 

public class A 
{ 
    int id { get; set; } 
} 
public class B : A 
{ 
} 

Bに設定する共分散であるが、新しいAにBを設定すると、コンパイルエラーで失敗した、作品:私は、この例が動作することを期待します。明示的キャストを行っても、コンパイル時にエラーが発生します。これを行う方法はありますか、あるいは私は反共分散を完全に誤解していますか?

答えて

5

あなたは行うことはできません。

B b = new A(); 

単にABではありませんので。割り当てが無効です。私はこの分散と呼ぶことすらわかりません - それは単なる継承です。

b.SomeMethod(); 

のsomeMethod:Bは(bが実際にAオブジェクトへの参照を保持している場合)Aは、あなたがそれを行うには意味がないことが確認できていないメンバーを持っていた一般的なケースでは

B内でのみ定義されますが、このロジックは変数自体への代入に拡張されます。キャストを追加したとしても、キャストには暗黙的な型チェックが行われ、失敗します。

+0

これをクリアしていただきありがとうございます。それで、Bに文字列タイトルがあるとしましょう。私はAからBまでのすべてのメンバーを割り当ててから、別々にタイトルを割り当てたいと思います。明示的にすべてのプロパティを個別に割り当てることに加えて、ショートカットはありますか?それが私の実際の後のすべてです。 – DougJones

+0

@Doug - AutoMapper maybe?同様のモデル間で変更するためにシリアル化ラウンドトリップを使用することも知られていませんが、AutoMapperはおそらく最も簡単なオプションです。 –

+0

素晴らしい... AutoMapperプロジェクトについて聞いたことがありませんでした。それは私の効率化に役立ちますが、暗黙のキャストが機能し、実行時の効率を維持すると考えていました。とにかく、今私は知っている...再び感謝します。 – DougJones

1

キャストルールに違反しているわけではありません。それはのような状況で適用されます。

void WithApple(Action<Apple> eat); 

、あなたが果物のいずれかの種類を食べる方法を知っているいくつかの方法があるとします。

void EatFruit(Fruit fruit); 

それは果物の任意の種類を食べることができるので、あなたがする必要があります言うことができる:

代理人が正確に一致しなければならなかったように、これはcontravarianceサポートする前にこれは不可能でした。

これはもう少し直感的な概念である共分散、区別される:

次のことができるようにする必要があり
void EatAllFruit(IEnumerable<Fruit> inBasket); 

IEnumerable<Apple> apples = someBasket; 
EatAllFruit(apples); 
6

私は完全にcontravarianceを誤解しますか?

はい。 は、「共分散」と「コントラバリエーション」がを意味するものと完全に完全に誤解されています。あなたは割り当ての互換性と混同しています。

これは非常に一般的なエラーです。 2つの概念は関連していますが、はまったく同じではありませんです。

割り当ての互換性は、1つの型の式を別の型の変数に格納できるプロパティです。

共分散は、型から型へのマッピングによって方向の割り当ての互換性が維持されるというプロパティです。 GiraffeがAnimalと割り当て互換性があり、これがIEnumerable<Giraffe>IEnumerable<Animal>と割り当て互換性があることを意味する場合、IEnumerable<T>マッピングは共変量です。

は、より多くの詳細については、テーマに関する私の記事を参照してください:共分散

はい、それは作品であるB作品に設定

http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx

。 "a"はと割り当て互換であり、ではない "共分散" は何も変化がありませんです。割り当て "a = B"で使用される割り当ての互換性の方向を保持するタイプからタイプへののマッピングはではありません。何も一般的ではありません。

ただし、bを新しいAに設定するとコンパイルエラーが発生します。

正しいです。

これを行う方法はありますか?

いいえ「A」と「B」の代わりに、「動物とキリン」と呼んでください。すべてのキリンは動物です。変数が動物を保持できる場合は、それはキリンを保持することができます。逆にしようとすると、AnimalをGiraffe型の変数に入れることはできません。動物は実際には虎であるかもしれません。あなたはタイガーをキリンの変数に入れることを許可されるべきですか?

+0

私はこれを正しく読まないと思う。 「割り当ての互換性の方向を保持する型から型へのマッピングはありません」と述べています。 'T - > IEnumerable 'はどうでしょうか?次に 'T 'が' U'型の変数に代入可能である場合、 'IEnumerable 'が 'IEnumerable '型の変数に代入可能な場合もあります。逆に、 'T'のインスタンスが 'U '型の変数に代入可能でない場合、' IEnumerable 'の変数の場合、' IEnumerable 'のインスタンスについても同様である。これは、型の互換性を保持する型から型へのマッピングのようです。 – jason

+0

@ Jason:「あなたのプログラムでこのようなマッピングは使用されていません」という意味でした。私はテキストを更新しました。 –

+0

+1ありがとうございます!それは私の共分散を解消します。私は、反差異の理解に取り組むのにもう少し時間を費やす必要があります。 – DougJones

関連する問題