我有两个界面:

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<>的实现中ClassBIAmA的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的回答。

10-06 07:10