.NET 4.0 Cast通用接口

use*_*730 4 .net generics casting interface

我有两个接口,其中一个是通用接口,只允许从第二个接口派生的类型.它们看起来像这样:

public interface IProvider<T> where T : IContent
{
    T getContent(int i);
    void addContent(T content);
}
public interface IContent
{
    string whatIAm();
}
Run Code Online (Sandbox Code Playgroud)

当然,我真正的界面更复杂,但它应该显示我的问题是什么.现在我为每个接口都有一个具体的类:

public class Provider : IProvider<FileContent> 
{
    public FileContent getContent(int i)
    {
        return null;
    }
    public void addContent(FileContent content)
    {
    }
}

public class FileContent : IContent{
    public string whatIAm(){
        return "FileContent";
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的代码中,我想使用引用类型"IProvider",但演员出错...请看这个例子:

 static void Main(string[] args)
    {
        Provider p = new Provider(); //works
        IProvider<FileContent> pp = p as IProvider<FileContent>; //also works
        IProvider<IContent> ppp = pp as IProvider<IContent>; //fails :(
    }
Run Code Online (Sandbox Code Playgroud)

ppp永远是空的.我必须改变这个演员是如何工作的?提前致谢.

Bot*_*000 6

type参数必须完全匹配.IProvider<IContent>是一种不同的类型IProvider<FileContent>,它们之间没有继承.

想象一下,你有一个IProvider<IContent> ppp  来自你IProvider<FileContent>和开发人员的尝试ppp.addContent(someOtherContentThatIsNoFileContent).该声明是有效的IProvider<IContent>,但它会打破类型安全,所以不允许这样的转换是正确的做法. 

泛型类型参数的协方差和反演在某些情况下允许这样的事情,但由于您的接口使用type参数作为in-和output参数,因此它不会像现在声明的那样适用于它.

编辑:看看IEnumerable定义:

public interface IEnumerable<out T> 
Run Code Online (Sandbox Code Playgroud)

所以你知道IEnumerable T只用作输出参数(你不能添加项,只能枚举它们),而out关键字指定T是协变的.所以你可以做到

IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;
Run Code Online (Sandbox Code Playgroud)

如果要执行此操作,则必须add从界面中删除该方法.同样适用于输入参数和in泛型类型参数上的关键字. 

您的界面将如下所示:

public interface IProvider<out T> where T : IContent
{
    T getContent(int i);
}
Run Code Online (Sandbox Code Playgroud)