2011-06-17 3 views
9

a previous questionの質問に続き、これは共分散の問題として識別されています。List <T>が共変なインターフェイスで無効なのはなぜですか?MyInterface

class Program 
{ 
    static void Main(string[] args) 
    { 
     IFactory<IProduct> factory = new Factory(); 
    } 
} 

class Factory : IFactory<Product> 
{ 
} 

class Product : IProduct 
{ 
} 

interface IFactory<out T> where T : IProduct 
{ 
    List<T> MakeStuff(); 
} 

interface IProduct 
{ 
} 

は私が取得:次のように私はIFactoryを変更した場合、さらにこの1歩を踏み出し

無効な差異:型パラメータTがSandbox.IFactory.MakeStuff上の不変有効である必要があります()。 Tは共変数である。

なぜこれは不変ではありませんか?これはどのように解決できますか?

答えて

7

@Craig's answerが正しいです。解決するには、それを変更します。

IEnumerable<T> MakeStuff() 

EDIT:理由として、IEnumerable<T> Interfaceの定義を見て:IList<T> Interfaceは、outキーワードを持っていないことを

public interface IEnumerable<out T> : IEnumerable 

注意を。差異は、クラスではなくインターフェイスと代理人のジェネリック型パラメータでサポートされているため、List <T>には適用されません。

+2

この回答が書かれた後、 'List 'が新しいインターフェース 'IReadOnlyList 'を実装した新しいバージョンの.NET Frameworkがリリースされたことに注意してください。示されているように、インタフェースは 'IEnumerable 'のように共変です。 –

6

List<T>からオブジェクトを追加または削除できるため、リストが関数結果であっても、Tは常に不変でなければなりません。 var l = MakeStuff()を実行すると、リストに項目を入れたり取り出したりできるので、Tは不変でなければなりません。

+0

解決方法 – Firoso

+0

'MakeStuff'には異なる戻り値の型を使います。 –

11

他の回答は正しいが、コンパイラがこれを安全でないとフラグする理由を推論するのは有益である。私たちがそれを許したとしよう。何がうまくいかないでしょうか?

class Sprocket: Product {} 
class Gadget : Product {} 
class GadgetFactory : IFactory<Gadget> 
{ 
    public List<Gadget> MakeStuff() 
    { 
     return new List<Gadget>() { new Gadget(); } 
    } 
} 
... later ... 
IFactory<Gadget> gf = new GadgetFactory(); 
IFactory<Product> pf = gf; // Covariant! 
List<Product> pl = pf.MakeStuff(); // Actually a list of gadgets 
pl.Add(new Sprocket()); 

ちょっと、ガジェットだけを含むリストにスプロケットを追加しました。

コンパイラが問題を検出できる場所は1つだけあり、それはインターフェイスの宣言にあります。

ご迷惑をおかけして申し訳ございません。私はもっ​​と良いものを考え出すことができませんでした。

+0

フィードバックいただきありがとうございます、私はより多くの背景を持っていただければ幸いです、私は思っていただけでなく、共謀や反共を理解していないようです。あなたの不変性シリーズのパート4をリリースします.-P – Firoso

関連する問題