次のC#コードがなぜコンパイルされないのか理解できません。
ご覧のとおり、IEnumerable<T>
パラメーターを持つ(そしてT
はIA
インターフェースに制限されている)静的な汎用メソッドSomethingがあります。このパラメーターをIEnumerable<IA>
に暗黙的に変換することはできません。
説明は何ですか? (私は回避策を探しません、なぜそれがうまくいかないのか理解するために)。
public interface IA { }
public interface IB : IA { }
public class CIA : IA { }
public class CIAD : CIA { }
public class CIB : IB { }
public class CIBD : CIB { }
public static class Test
{
public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA
{
var bar = foo.ToList();
// All those calls are legal
Something2(new List<IA>());
Something2(new List<IB>());
Something2(new List<CIA>());
Something2(new List<CIAD>());
Something2(new List<CIB>());
Something2(new List<CIBD>());
Something2(bar.Cast<IA>());
// This call is illegal
Something2(bar);
return bar;
}
private static void Something2(IEnumerable<IA> foo)
{
}
}
Something2(bar)
行に表示されるエラー
引数1: 'System.Collections.Generic.List'から 'System.Collections.Generic.IEnumerable'に変換できません
エラーメッセージは十分に有益ではありません、そしてそれは私のせいです。それについてすみません。
あなたが経験している問題は、共分散が参照型にのみ作用するという事実の結果です。
あなたはたぶん「今IA
は参照型です」と言っているでしょう。はい、そうです。しかし、T
が IA
と等しいとは言わなかった。 T
は が IA
を実装する型であり、 値型はインターフェースを実装することができます 。したがって、共分散が機能するかどうかはわかりません。また、それを許可しません。
共分散を機能させたい場合は、typeパラメーターがclass
制約およびIA
インターフェース制約を持つ参照型であることをコンパイラーに伝えなければなりません。
共分散には参照型の保証が必要であるため、エラーメッセージには変換が不可能であることが実際には伝えられます。これが基本的な問題であるためです。
私はEricの優れたインサイダー回答を、一般的な制約に慣れていないかもしれないコード例で補完したいだけでした。
Something
のシグネチャを次のように変更します。class
制約 が最初にくる必要があります 。
public static IList<T> Something<T>(IEnumerable<T> foo) where T : class, IA