Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.NET 4.0强制转换通用接口_.net_Generics_Interface_Casting - Fatal编程技术网

.NET 4.0强制转换通用接口

.NET 4.0强制转换通用接口,.net,generics,interface,casting,.net,Generics,Interface,Casting,我有两个接口,其中一个是泛型接口,只允许从第二个接口派生的类型。它们看起来像这样: public interface IProvider<T> where T : IContent { T getContent(int i); void addContent(T content); } public interface IContent { string whatIAm(); } 公共接口i提供程序,其中T:IContent { T getContent(i

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

public interface IProvider<T> where T : IContent
{
    T getContent(int i);
    void addContent(T content);
}
public interface IContent
{
    string whatIAm();
}
公共接口i提供程序,其中T:IContent
{
T getContent(inti);
空隙率(T含量);
}
公共接口IContent
{
字符串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
{
公共文件内容getContent(inti)
{
返回null;
}
public void addContent(FileContent)
{
}
}
公共类文件内容:IContent{
公共字符串whatIAm(){
返回“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 :(
    }
static void Main(字符串[]args)
{
Provider p=new Provider();//有效
IProvider pp=p作为IProvider;//也可以使用
IProvider ppp=pp作为IProvider;//失败:(
}
ppp
始终为空。我必须更改什么才能使此强制转换生效?
提前感谢。

这不是C#中泛型的工作方式。
IProvider
的泛型不是
IProvider
的子类型,类型参数必须完全匹配。
IProvider
是与
IProvider
不同的类型,它们之间没有继承关系

假设您的
IProvider中有一个
IProvider ppp
,开发人员尝试
ppp.addContent(其他一些不是文件内容的内容)
。该语句对
IProvider
有效,但会破坏类型安全,因此不允许这样的转换是正确的

在某些情况下允许这样做,但由于您的接口同时使用类型参数作为in和output参数,因此现在声明的方式将不适用于它

编辑:查看
IEnumerable
的定义:

public interface IEnumerable<out T> 
如果要执行此操作,必须从界面中删除
add
方法。这同样适用于输入参数和泛型类型参数中的
关键字

然后,您的界面将如下所示:

public interface IProvider<out T> where T : IContent
{
    T getContent(int i);
}
公共接口i提供程序,其中T:IContent
{
T getContent(inti);
}
你写的

Provider p = new Provider(); //works
IProvider<FileContent> pp = p as IProvider<FileContent>; //also works
IProvider<IContent> ppp = pp as IProvider<IContent>; //fails :(
其中
NonFileContent
是一个实现
IContent
的类,但不是从
FileContent
派生的

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

FileContent fc = pp.getContent(0);

刚才添加的对象应该被返回。但是,它是一个<代码>非FieleCuttEng/Engult>实例,而不是 FieleCuthOnt/Cux>实例。因此,从一个返回值必须是<代码>文件内容> /代码>实例的方法中返回这个对象是不可能的,这就是编译器不考虑<代码> PP< /代码>和>的原因。code>ppp

assignment首先是兼容的。

这可能是的副本。这正是我想要达到的。正如我在问题中所写的:我必须改变什么才能使此强制转换生效?我已经尝试删除IProvider界面中的两个方法之一-但无论删除哪一个,强制转换仍然有效不起作用:(@user1531730评论太长了,我更新了我的答案。@user1531730很高兴听到。:)我想你需要将你的界面分成两个界面。好的,我想你应该开始理解为什么它不起作用。但是参考Botz3000发布的链接,如果我删除
void addContent(T content)应该是可能的
方法,但这也不起作用。
ppp.addContent(new NonFileContent());
FileContent fc = pp.getContent(0);