.NET 4.0 Cast通用接口

时间:2012-07-17 12:27:24

标签: .net generics interface casting

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

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

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

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";
    }
}

在我的代码中,我想使用引用类型“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 :(
    }

ppp始终为空。我必须改变这个演员是如何工作的? 提前谢谢。

3 个答案:

答案 0 :(得分:6)

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

想象一下,您的IProvider<IContent> ppp中有IProvider<FileContent>,开发人员会尝试ppp.addContent(someOtherContentThatIsNoFileContent)。该语句对IProvider<IContent>有效,但它会破坏类型安全性,因此不允许进行此类转换是正确的做法。

Covariance and Contravariance for generic type parameters在某些情况下允许这样的东西,但由于你的接口使用type参数作为in-和output参数,这不会像现在声明它那样适用于它。

编辑:查看IEnumerable的定义:

public interface IEnumerable<out T> 

因此,您知道IEnumerable仅将T用作输出参数(您无法添加项目,只能枚举它们),out关键字指定T是协变的。所以你可以做到

IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;

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

您的界面将如下所示:

public interface IProvider<out T> where T : IContent
{
    T getContent(int i);
}

答案 1 :(得分:3)

这不是C#中的通用工作方式。 IProvider<FileContent>的通用不是IProvider<IContent>的子类型。

答案 2 :(得分:1)

你写了

Provider p = new Provider(); //works
IProvider<FileContent> pp = p as IProvider<FileContent>; //also works
IProvider<IContent> ppp = pp as IProvider<IContent>; //fails :(

让我们假设所有这三个都有效。然后就可以编写以下内容:

ppp.addContent(new NonFileContent());

其中NonFileContent是一个实现IContent的类,但不是从FileContent派生的。

现在,想象一下以下调用中会发生什么:

FileContent fc = pp.getContent(0);

刚刚添加的对象应该被返回。但是,它是NonFileContent实例,而不是FileContent实例。因此,从返回值必须为FileContent实例的方法返回此对象是不可能的,这就是编译器首先不考虑ppppp赋值兼容的原因。