C# 为什么我不能从受约束的泛型集合推断接口?
我有一段代码是这样工作的:C# 为什么我不能从受约束的泛型集合推断接口?,c#,generics,covariance,contravariance,C#,Generics,Covariance,Contravariance,我有一段代码是这样工作的: public IEnumerable<ICacheMember> Flubvert( IEnumerable<ICacheMember> members ) { // do some stuff to members return members; } ExecuteFlubversion<ICacheMemberSub>(cacheMember); public IEnumerab
public IEnumerable<ICacheMember> Flubvert( IEnumerable<ICacheMember> members )
{
// do some stuff to members
return members;
}
ExecuteFlubversion<ICacheMemberSub>(cacheMember);
public IEnumerable Flubvert(IEnumerable成员)
{
//对会员做些事情
返回成员;
}
然而,我不明白为什么我不能这样做:
public IEnumerable<T> ExecuteFlubversion<T>( IEnumerable<T> memberList ) where T: class,ICacheMember
{
return Flubvert( memberList );
}
public IEnumerable ExecuteFlubversion(IEnumerable成员列表),其中T:class,ICacheMember
{
返回Flubvert(成员列表);
}
当然,泛型上的约束应该保证
memberList
是ICacheMember
类型的IEnumerable?我是否真的需要将现有(但隐式)的ICacheMember
对象的集合转换为显式ICacheMember
对象,然后再将它们转换回来?我可以理解,鉴于Flubvert
的方法签名,我可能需要将它们转换回来,但我不明白为什么我必须在方法调用中转换它们。这就是我在工作代码中所做的,但它似乎完全不符合泛型的一般优雅行为,因此我想我一定是误解了这应该如何操作。首先是IEnumerable
(和其他泛型类型)的协方差仅当T
是引用类型时才起作用,因此您需要:
public IEnumerable<ICacheMember> ExecuteFlubversion<T>(IEnumerable<T> memberList)
where T: class, ICacheMember // NOTE 'class'
{
var flub = Flubvert(memberList); // can you call with 'memberList'?
return flub; // can you return that type?
// depending on what 'Flubvert' does, maybe return 'IEnumerable<T>'
// and say:
// return (IEnumerable<T>)flub;
}
public IEnumerable ExecuteFlubversion(IEnumerable成员列表)
其中T:class,ICacheMember//NOTE'class'
{
var flub=Flubvert(memberList);//您能用“memberList”调用吗?
return flub;//您能返回该类型吗?
//根据“Flubvert”的作用,可能会返回“IEnumerable”
//然后说:
//返回(IEnumerable)flub;
}
还要注意,我更改了返回值。C#编译器无法保证从非泛型的Flubvert
方法返回的对象比IEnumerable
更具体,假设您有:
interface ICacheMemberSub : ICacheMember
{
...
}
你可以这样调用你的函数:
public IEnumerable<ICacheMember> Flubvert( IEnumerable<ICacheMember> members )
{
// do some stuff to members
return members;
}
ExecuteFlubversion<ICacheMemberSub>(cacheMember);
ExecuteFlubversion(cacheMember);
此函数将尝试返回类型为
IEnumerable
的对象,但该对象不一定可强制转换为IEnumerable
,因此会出现错误。如果不直接回答问题,能否将Flubvert的签名更改为泛型?如果将Flubvert设置为泛型,则方法代码的其余部分将保持不变,并且您仍然可以假定成员将是ICAchember的实现者
public IEnumerable<T> Flubvert<T>(IEnumerable<T> members)
where T : class, ICacheMember
{
// do some stuff to members
return members;
}
public IEnumerable<T> ExecuteFlubversion<T>(IEnumerable<T> memberList)
where T : class,ICacheMember
{
return Flubvert(memberList);
}
public IEnumerable Flubvert(IEnumerable成员)
其中T:class,ICacheMember
{
//对会员做些事情
返回成员;
}
公共IEnumerable ExecuteFlubversion(IEnumerable成员列表)
其中T:class,ICacheMember
{
返回Flubvert(成员列表);
}
这是一个关于协方差和逆变换的问题。别担心,Jon Skeet很快就会来解释。你为什么要添加一个间接层次?你在作曲吗?Bridge?实现ICacheMember
的每个类都是一个ICacheMember
,但不是ICacheMember
的每个实现都来自实现它的某个类。@dariogriffo我没有时间打牌,我正忙着去理解协方差:p我之所以添加间接,是因为Flubvertion过程(在我当前的示例中,一个从自定义查询系统构建的搜索/过滤机制)对ICacheMember接口非常感兴趣,它可以由缓存中找到的任何类型实现,所有类型都应该以相同的方式进行Flubvertable内部Flubvert
看起来像什么?你能保证成员
参数永远不会被赋值吗?因为这样你就可以解决你的问题(编辑)通过从IEnumerable
到IEnumerable
的简单转换解决问题,其中T
由您的泛型方法定义。很好,我的代码中有这一点,因此我将更新问题。不会影响我所困惑的特定行为。@glenatron您的原始代码(编辑前)给出了编译时错误,因为泛型中的协方差仅适用于引用类型。新代码给出了另一个编译时错误。调用Flubvert(memberList)
现在很好。问题在于返回
部分。正如我指出的,C#编译器无法知道非泛型方法返回什么IEnumerable
,只是它与IEnumerable
兼容。例如,它实际上可能是列表
,而不是T的列表
de>。这样的列表中可能还有其他奇怪的东西。
。是的,你完全正确。正如我在问题中所说的,我知道我需要显式转换或更改返回签名,我非常感兴趣的是为什么我不能调用该方法。@glenatron你可以调用该方法。我将用两行代码编写你的泛型方法,以让它更清晰。编辑。你是对的,我可以。太好了,现在我不明白为什么一开始就有问题。我发誓,它之前肯定不起作用:/