Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.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
C# T必须是反变有效的_C#_.net_Generics_Covariance_Contravariance - Fatal编程技术网

C# T必须是反变有效的

C# T必须是反变有效的,c#,.net,generics,covariance,contravariance,C#,.net,Generics,Covariance,Contravariance,这有什么问题 interface IRepository<out T> where T : IBusinessEntity { IQueryable<T> GetAll(); void Save(T t); void Delete(T t); } 接口i假设,其中T:IBusinessEntity { IQueryable GetAll(); 无效保存(T); 无效删除(T); } 它说: 无效差异:类型参数“T”在“MyNamespace.I

这有什么问题

interface IRepository<out T> where T : IBusinessEntity
{
    IQueryable<T> GetAll();
    void Save(T t);
    void Delete(T t);
}
接口i假设,其中T:IBusinessEntity
{
IQueryable GetAll();
无效保存(T);
无效删除(T);
}
它说:


无效差异:类型参数“T”在“MyNamespace.IRepository.Delete(T)”上必须相反有效T’是协变的。

以下两种方法是错误的:

void Save(T t);
void Delete(T t);
不能将
t
作为方法参数。如果希望它在泛型定义中是协变的(
out T
),则仅作为返回类型

或者,如果希望使用逆变,则可以仅将泛型参数用作方法参数,而不使用返回类型:

interface IRepository<in T> where T : IBusinessEntity
{
    void Save(T t);
    void Delete(T t);
}
接口i假设,其中T:IBusinessEntity
{
无效保存(T);
无效删除(T);
}

您只能协变地使用
out
类型参数,即在返回类型中。因此,
IQueryable GetAll()
是正确的,但是
void Delete(T)
不是

由于
T
在您的类中同时使用并列和倒数形式,因此此处不能使用
out
(也不能使用
in

如果你想更多地了解这背后的理论背景,请稍作休息,阅读下面的文章


欢迎回来。那么,如果您需要存储库中的所有这些方法,但仍然需要一个协变接口,您会怎么做?您可以将协变部分提取到其自己的接口中:

interface IDataSource<out T> where T : IBusinessEntity
{
    IQueryable<T> GetAll();
}

interface IRepository<T> : IDataSource<T> where T : IBusinessEntity
{
    void Save(T t);
    void Delete(T t);
}
接口IDataSource,其中T:IBusinessEntity
{
IQueryable GetAll();
}
接口IRepository:IDataSource其中T:IBusinessEntity
{
无效保存(T);
无效删除(T);
}

这也是.NET BCL解决此问题的方法:
IEnumerable
是协变的,但只支持“读取操作”
ICollection
IEnumerable
的一个子类型,允许读写操作,因此本身不能是协变的。

考虑一下如果编译器允许:

interface IR<out T>
{
    void D(T t);
}

class C : IR<Mammal>
{
    public void D(Mammal m)
    {
        m.GrowHair();
    }
}
...
IR<Animal> x = new C(); 
// legal because T is covariant and Mammal is convertible to Animal
x.D(new Fish()); // legal because IR<Animal>.D takes an Animal
接口IR
{
无效D(T);
}
C类:红外
{
公共空间D(哺乳动物m)
{
m、 长发();
}
}
...
IR x=新的C();
//合法,因为动物是协变的,哺乳动物可以转换为动物
x、 D(新鱼());//因为IR.D带走一只动物是合法的
你只是想在鱼身上长头发


“out”表示“T仅用于输出位置”。您在输入位置使用它。

请注意,它可以在参数中,但只能使用类似于
操作的操作来再次反转方向。完整且清晰的回答。谢谢,现在我终于明白为什么关键字是
in
out
。类的输入和类的输出。这已经是一段时间的斗争了,谢谢。你最后做了什么?我也面临同样的问题。答案并不能真正解决问题;我需要在同一类中获取、保存和删除。对不起,我不记得了。那是4年前的事了。我永远无法理解为什么在解释某事时,
T
IR
C
x
是有效的变量名。这也适用于MSDN文档,尤其是泛型文档。什么是“D”?@David:它们是有效的,因为它们符合C#规范中的标识符标准,但我认为你的意思是在教学上有效。使用短名称的教学法是要巧妙地提醒读者,这是一个普遍的、广泛适用的例子,他们应该抽象地思考,而不是解决特定领域中的特定问题。从教学学上讲,这不是有效的。。。当例子把概念带到脑海中,而符号带来的意义远远不是概念化。但这远远不是方差。我希望我在第一次尝试学习协方差/逆变时看到这个解释:“out”表示“T”仅用于输出位置。您正在输入位置使用它。”我刚才假设
in
out
是任意重用的关键字。@AndrewKeeton:我们经历了一个漫长的设计过程,考虑了许多选项。与所有设计过程一样,有许多相互竞争的因素必须相互权衡。请参阅我2007年关于该主题的文章,了解一些选项及其优缺点: