我有两个界面:
public interface IAmA
{
}
public interface IAmB<T> where T : IAmA
{
}
还有两个实现这些接口(interface)的类,如下所示:
public class ClassA : IAmA
{
}
public class ClassB : IAmB<ClassA>
{
}
尝试使用这些类时,如下所示:
public class Foo
{
public void Bar()
{
var list = new List<IAmB<IAmA>>();
list.Add(new ClassB());
}
}
我收到此编译器错误:
cannot convert from 'ClassB' to 'IAmB<IAmA>'
我知道我可以使用以下方法使编译器满意:
public class ClassB : IAmB<IAmA>
{
}
但是我需要能够成为
IAmB<>
的实现中ClassB
的IAmA
的Type参数。 最佳答案
快速的答案是,您可以通过将IAmB<T>
的类型参数声明为协变量来做您要的事情,只有当该类型用作返回类型时:
public interface IAmB<out T> where T : IAmA
{
T SomeMethod(string someparam);
}
out T
意味着您可以使用比约束中指定的类型更具体的类型。您将无法使用T作为参数。以下内容无法编译:
public interface IAmB<out T> where T : IAmA
{
void SomeMethod(T someparam);
}
从文档中
这不是一个编译器怪癖。
假设您可以声明一个协变方法参数,则列表最终将包含一些无法处理
IAmB<IAmA>
参数的对象-他们期望输入ClassA或更具体。您的代码可以编译,但在运行时失败。哪个提出了问题-为什么要使用
IAmB<ClassA>
?不过,您应该在使用此功能之前考虑一下,因为可能还有其他更合适的方法来解决实际问题。使用实现具体类型的通用接口(interface)但尝试像使用其他接口(interface)一样使用它是不寻常的。
您可以查看MSDN文档中有关Covariance and Contravariance的部分,以及Eric Lippert的Jon Skeet对this SO question: Difference between Covariance and Contravariance的回答。