多态性 - 我没有得到什么?

时间:2013-07-21 14:43:31

标签: c# c#-4.0 polymorphism

我在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; }
}

3 个答案:

答案 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" } };