4

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

3 回答 3

4

这是一个方差问题,而不是多态性问题。

如果 List-of-Foo 也是 IList-of-IBar,则以下内容将起作用:

class Another : IBar {}
IList<IBar> list = new List<Foo>();
list.Add(new Another());

然后我们将另一个添加到 Foo 列表中。这是一个错误。编译器阻止你犯错误。

请注意,最近的编译器/.net 版本通过“in”/“out”支持差异。所以 List-of-Foo 可以作为 IEnumerable-of-IBar。因为这保证只返回Foo (不接受它们),并且所有 Foo 也是 IBar - 因此它是安全的。

于 2013-07-21T14:52:15.557 回答
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);
}
于 2013-07-21T14:55:15.893 回答
0
var list = new List<Foo>

该列表是一个List<Foo>,而不是一个List<IBar>。即使Foo实现IBar了,列表本身仍然是一个列表Foo

因此,您不能将实现的任何其他类型添加IBar到该列表中。只有Foo's,这显然是 aFoo或任何派生自Footoo 的类型,因为那也将是 a Foo。我说Foo的太多了。

如果您希望添加任何实现的类型IBar,则可以将列表设为以下集合IBar

var list = new List<IBar> { new Foo { Name = "Item" } };
于 2013-07-21T14:46:42.513 回答