3


1

私は一般的なConstrainedクラスによって実装されている一般的なインターフェースIConstrainedを持っています。 以下のコードを実行しようとすると、無効なキャスト例外が発生します。

IConstrained decimalLimit = new Constrained(1); IConstrained similarLimit =(IConstrained)decimalLimit;

decimalがIComparableを実装している場合、なぜこれができないのですか? これを行う正しい方法は何でしょうか。 ありがとう。

7 Answer


7


http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx[ジェネリック型は.NET 2.0では共変ではありません。ランタイム。 ただし、 http://blogs.msdn.com/charlie/archive/2008/10/28/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx[.NET 4.0は共分散をサポートする]。


4


IConstrainedからIConstrainedへのキャストは共分散と呼ばれます。 C#3ではできません。 しかし、それはC#4に入ってきています。

Erik Lippertは、 Contravariance and Covarianceについて詳しく説明した一連のブログ記事を掲載しています。

それを回避するには、使用するときに小数をIComparableにキャストする必要があります。


1


これはC#での一般的なトリップアップ(およびGenericsでの他の言語)です。

C#では、クラス階層内のクラス(スーパークラス、サブクラス)にのみキャストできます。 しかし、decimalはIComparableを実装していますが、 IConstrained`はスーパークラスでも IConstrained`のサブクラスでもありません。 C#がこれを許可しないのは、それを許可することはあなたが非常に悪いことをすることができることを意味するからです。

これがなぜであるかの詳細な説明に関しては、https://stackoverflow.com/questions/6557/in-c-why-cant-a-liststring-object-be-stored-in-a-listobject-variableを参照してください。似たような質問]


1


このようにクラスをキャスタブルにするには、 `IConstrainedとIConstrained`の両方のインターフェースを実装する必要があります。

クラスA:IConstrained、IConstrained
NET 2.0は共分散または反分散を実装していないため、これは自動的には起こりません。 IConstrained`は IConstrained`を実装していません。 はい、それはイライラしますが直感に反します。 私が理解していることから、何らかの形でC#4.0でこの種のシナリオを実際にはある程度サポートするでしょう。 これは共分散または反分散と呼ばれます。

編集:私はConstrainedクラスに精通しているわけではありませんが、新しい `Contrained`を構築してそれに小数を渡すことができるかもしれません。 もしそれが `Constrained(T copyFrom)`という形式のコンストラクタを持っていたら、新しい `Constrained`を宣言してそれに小数を渡すことができます。 コピーを作るのが好きです。

編集2:このページの半分くらい下に "2.0"を検索してください。NET2.0でこの問題を回避する方法の例があります。http://blog.tlk.com/dot-net/2009/c-シャープ4共分散 - 反分散


1


これが「やり方」に対する答えです。

IList decimalLimit = new List(1); IEnumerable asComparable = decimalLimit.Cast(); IList similarLimit = asComparable.ToList();


0


総称に関しては、異なる型引数を持つ同じ総称型の2つのインスタンスは、互いに直接の関係はありません。 言い換えると:

IConstrained!== IConstrained

これは分散問題です。 decimalはIComparableですが、IConstrainedはIConstrainedではありません。 この種の自動変換は、C#4.0で改善されたco / contravarianceによって可能になると思います。 ただし、C#3.0以前では不可能です。


-1


逆分散と共分散について読んでください。 C#のジェネリックは不変であり、求めているものは望んでいるものではないことを理解してください。