以下内容不在fm.AddFoo(new StringFoo())上编译;错误消息:
参数1:无法从“ClassLibrary2.StringFoo”转换为“ClassLibrary2.IFoo”
这对我来说似乎合乎逻辑,因为字符串继承自object。
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
}
}
由于
答案 0 :(得分:1)
虽然看起来IFoo是IFoo的子类,但事实并非如此。当你关闭IFoo&lt;&gt;时到特定类型是不是从IFoo创建IFoo的子类,它们是单独的,不同的类型,没有共同的层次结构。
答案 1 :(得分:1)
如果你可以使你的IFoo<>
界面 协变 ,那就可以了,也就是说,如果你被允许将其声明更改为:
public interface IFoo<out T>
(注意out
)。由于协方差,任何IFoo<string>
也都是IFoo<object>
,因为string
是引用类型,并且派生自object
。
但是: IFoo<>
方法的Handle
成员以逆向方式使用type参数。因此,您的界面不能被声明为协变(out
)。 (它可以被声明为逆变(in
),但是对于上面的例子,它的方向是错误的。)
阅读仿制药中的协方差和逆变。
这里的根本问题是你的StringFoo
只处理字符串。因此,它永远不能用作IFoo<object>
,因为您可以传递Giraffe
实例(Giraffe
派生自object
,因此Giraffe
是object
进入StringFoo
,当Handle
取string
时,这是不可能的。