C# 无效差异:类型参数';T';必须在';UserQuery.IItem<;T>;。项目列表'';T';是协变的

C# 无效差异:类型参数';T';必须在';UserQuery.IItem<;T>;。项目列表'';T';是协变的,c#,covariance,C#,Covariance,为什么属性在方法可以编译时得到错误 public interface IFoo {} public interface IBar<out T> where T : IFoo {} public interface IItem<out T> where T: IFoo { // IEnumerable<IBar<T>> GetList(); // works IEnumerable<IBar<T>> Item

为什么属性在方法可以编译时得到错误

public interface IFoo {}
public interface IBar<out T> where T : IFoo {}

public interface IItem<out T> where T: IFoo
{
    // IEnumerable<IBar<T>> GetList(); // works
    IEnumerable<IBar<T>> ItemList { get; set; } // Error!
}
公共接口IFoo{}
公共接口IBar,其中T:IFoo{}
公共接口项,其中T:IFoo
{
//IEnumerable GetList();//有效
IEnumerable ItemList{get;set;}//错误!
}
错误:

无效差异:类型参数“T”必须是反向有效的 在“UserQuery.IItem.ItemList”上T’是协变的


您得到编译器错误是因为您有一个属性getter(
get
)和一个setter(
set
)。属性getter的输出中有
T
,因此
out
可以工作,但属性setter的输入中将有
T
,因此需要
in
修饰符

因为您在
T
上有
out
,所以需要删除setter,它将编译:

public interface IItem<out T> where T : IFoo
{
    // IEnumerable<IBar<T>> GetList(); // works
    IEnumerable<IBar<T>> ItemList { get; } // also works
}

但是您不能同时拥有两个(
out,in
),因此您不能拥有具有getter和setter的co/conversative属性。

不允许使用setter,因为如果是这样,您可以执行以下操作:

public interface ISubFoo : IFoo { }

IItem<ISubFoo> item = //whatever
item.ItemList = new List<IBar<IFoo>>>();
公共接口ISubFoo:IFoo{}
IItem item=//随便什么
item.ItemList=新列表>();

这是不安全的。

我不明白这一点。你已经联系了出去,进去,集合。为什么我不能使用out,因为out只是指“这个类型或任何派生类型”。如果B派生自A,那么为什么我不能将B传递给接口上需要A out A的任何属性,因为无论如何,B只能像A一样被调用。这是什么问题?这与我们有什么关系?in表示“此类型或任何基本类型”。我不希望这样,因为我希望至少使用A的行为集,传递“A”不会减少它。所以我不想“进去”…但我确实希望能够将B设置为A。
public interface ISubFoo : IFoo { }

IItem<ISubFoo> item = //whatever
item.ItemList = new List<IBar<IFoo>>>();