1

以下内容无法在线编译 fm.AddFoo(new StringFoo()); 带有错误消息:

参数 1:无法从 'ClassLibrary2.StringFoo' 转换为 'ClassLibrary2.IFoo'

这对我来说似乎是合乎逻辑的,因为字符串继承自对象。

public interface IFoo<T>
{
    void Handle(T value);
}

public class StringFoo : IFoo<string>
{
    public void Handle(string value)
    { }
}

public class ObjectFoo : IFoo<object>
{
    public void Handle(object value)
    { }
}

public class FooManager
{
    private readonly List<IFoo<object>> _foos;

    public FooManager()
    {
        _foos = new List<IFoo<object>>();
    }

    public void AddFoo(IFoo<object> foo)
    {
        _foos.Add(foo);
    }
}

public class Bad
{
    public Bad()
    {
        var fm = new FooManager();

        fm.AddFoo(new StringFoo()); \\ This does not compile
    }
}

谢谢

4

2 回答 2

1

虽然看起来 IFoo 是 IFoo 的子类,但它不是。当您将 IFoo<> 关闭到特定类型时,并不是从 IFoo 创建 IFoo 的子类,它们是独立且不同的类型,没有共同的层次结构。

于 2013-10-31T15:11:23.967 回答
1

如果你可以让你的IFoo<>接口协变它会起作用,也就是说,如果你被允许将它的声明更改为:

public interface IFoo<out T>

(注意out)。因为使用协方差 anyIFoo<string>也将是IFoo<object>因为string是引用类型并且派生自object.

但是:方法的成员IFoo<>Handle逆变方式使用类型参数。所以你的接口不能被声明为协变(out)。(它可以被声明为逆变的 (in) 但对于上面的示例来说,这方向是错误的。)

阅读泛型中的协变和逆变。

这里的基本问题是您StringFoo只处理字符串。因此它永远不能用作 anIFoo<object>因为你可以将例如一个Giraffe实例(Giraffe派生自object,所以 aGiraffe是 an object)传递给StringFoo,而当它Handle采用 a时这是不可能的string

于 2013-10-31T16:58:33.317 回答