我在C#中遇到多态问题。我有一个实现接口的对象,但是我不能将对象的集合表示为接口集合。面对我对多态性的理解,这就过去了。所以我想知道我哪里出错了。
[TestFixture]
class Tester
{
[Test]
public void Polymorphism()
{
var list = new List<Foo> {new Foo {Name = "Item"}};
Assert.That(list, Is.InstanceOf<IList>());
Assert.That(list[0], Is.InstanceOf<Foo>());
Assert.That(list[0], Is.InstanceOf<IBar>());
// why are the rest true but this false?
Assert.That(list, Is.InstanceOf<IList<IBar>>());
}
}
internal interface IBar
{
}
internal class Foo : IBar
{
public string Name { get; set; }
}
答案 0 :(得分:4)
这是一个方差问题,而不是多态性。
如果一个List of of Foo也是一个IList-of-IBar,那么下面的方法就可以了:
class Another : IBar {}
IList<IBar> list = new List<Foo>();
list.Add(new Another());
然后我们在Foo列表中添加了另一个。这是一个错误。编译器阻止你犯错。
请注意,最近的编译器/ .net版本通过“in”/“out”支持方差。因此,List of of Foo可以作为IEnumerable-of-IBar。因为只保证返回 Foo(不接受它们),所有Foo也都是IBar - 因此它是安全的。
答案 1 :(得分:1)
我也会把我的两分钱扔进去。如果您增加对协方差和逆变的理解,可以更好地理解您遇到的问题(参见http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx)。
我稍微修改了你的代码并提出了这个有效的测试方法:
public void TestMethod1()
{
var list = new List<Foo> { new Foo { Name = "Item" } };
Assert.IsNotNull(list as IList);
Assert.IsNotNull(list[0] as Foo);
Assert.IsNotNull(list[0] as IBar);
Assert.IsNotNull(list as IList<Foo>);
Assert.IsNotNull((IList<Foo>)list);
}
答案 2 :(得分:0)
var list = new List<Foo>
列表是List<Foo>
,而不是List<IBar>
。即使Foo
实现IBar
,列表本身仍然是Foo
的列表。
因此,您无法将任何其他实现IBar
的类型添加到该列表中。只有Foo
,显然是Foo
或任何来自Foo
的类型,因为它也是Foo
。我已经说过Foo
太多了。
如果您希望添加任何实现IBar
的类型,那么您可以将列表设为IBar
的集合:
var list = new List<IBar> { new Foo { Name = "Item" } };