C# 泛型集合冲突

C# 泛型集合冲突,c#,generics,covariance,C#,Generics,Covariance,这是我最好的尝试来重现这种情况 public interface IFoo { } public class Foo : IFoo { } public class Bar : IFoo { } public class CollectionOf<T> : List<IFoo> { } public class Bars : CollectionOf<Bar> { } public class Test { public void Te

这是我最好的尝试来重现这种情况

public interface IFoo
{

}

public class Foo : IFoo { }

public class Bar : IFoo { }

public class CollectionOf<T> : List<IFoo>
{

}

public class Bars : CollectionOf<Bar>
{

}

public class Test
{
    public void Test()
    {
        CollectionOf<IFoo> bars = new Bars();
    }
}
公共接口IFoo
{
}
公共类Foo:IFoo{}
公共类栏:IFoo{}
公共类集合:列表
{
}
公共类酒吧:收藏
{
}
公开课考试
{
公开无效测试()
{
钢筋收集=新钢筋();
}
}
编译器抱怨实例化。Bars是Ifoo的集合。这是协方差/反方差问题之一吗?

是的

如果允许这样做,您就可以将任何对象放入该集合中,只要它实现了
IFoo
接口,但这对集合来说并不安全

让我举例说明:

var b = new Bars();
CollectionOf<IFoo> bars = b;
bars.Add(Dummy); // implements IFoo, but does not descend from Bar
var b=新条();
棒的收集=b;
条。添加(虚拟);//实现IFoo,但不从Bar下降
此时,
b
包含什么?类型为
虚拟的对象
?那将是不好的,因此这首先是不允许的。

是的

想一想<代码>条应该能够合法地容纳实现
IFoo
的任何类型的对象。但是,
Bar
类型的对象只能容纳
Bar
类型的对象

使用您的代码这是允许的,这显然是错误的

CollectionOf<IFoo> bars = new Bars();
bars.Add( new Foo() );  // Uh oh!
CollectionOf bar=新条();
添加(新的Foo());//哦!

这将有效地破坏通过泛型提供给您的类型安全性。

如果有,修复将取决于什么不适合您。我可以用两种方式编译您的示例,要么使用IEnumerable,要么将CollectionOf定义为带有out泛型修饰符的接口。我不知道这两种方法是否适合你:

public interface IFoo { }

public class Foo : IFoo { }

public class Bar : IFoo { }

public interface CollectionOf<out T> : IEnumerable<IFoo> { }

public class Bars : CollectionOf<Bar> { }

public class Test
{
    public void Test()
    {
        IEnumerable<IFoo> bars1 = new Bars();
        CollectionOf<IFoo> bars2 = new Bars();
    }
}
公共接口IFoo{}
公共类Foo:IFoo{}
公共类栏:IFoo{}
公共接口集合:IEnumerable{}
公共类栏:集合{}
公开课考试
{
公开无效测试()
{
IEnumerable条1=新条();
棒材2的收集=新棒材();
}
}

谢谢@EdS。解决方法是什么?如果您希望支持协方差/逆变,我们需要知道
CollectionOf
是用于从集合中读取还是添加到集合中?它不能同时支持协方差和逆变。如果我承诺只在那个集合中放条会怎么样?这不是or的全部内容吗?如果您只想在集合中放置
Bar
,为什么不使用
CollectionOf Bar=new Bar()?@Matthew:不,他们不允许有不正确的行为。除非您仅通过界面工作,否则您永远无法将
Foo
添加到
条的集合中。这不是C++;泛型是强类型的。这种情况将确保形成你的例子,这将导致行为没有意义,也没有在标准中定义。谢谢你,是的,这是完美的,因为。在哪里玩?
或协方差意味着类
Foo
可以对其元素进行升级。例如,
foomyfoo=newfoo()。在这种情况下,
T
只能用于返回类型(因此为out)。要了解更多信息,请查看这个,我相信这就是我要寻找的。我需要从CollectionOf中删除,所以out是我所需要的。