我不明白为什么下面的C#代码无法编译。
如您所见,我有一个静态的泛型方法带有一个IEnumerable<T>
参数的东西(并且T
被约束为一个IA
接口),并且该参数不能为隐式转换为IEnumerable<IA>
。
解释是什么? (我不是在寻找解决方法,只是为了了解为什么它不起作用。)
public interface IA { }
public interface IB : IA { }
public class CIA : IA { }
public class CIAD : CIA { }
public class CIB : IB { }
public class CIBD : CIB { }
public static class Test
{
public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA
{
var bar = foo.ToList();
// All those calls are legal
Something2(new List<IA>());
Something2(new List<IB>());
Something2(new List<CIA>());
Something2(new List<CIAD>());
Something2(new List<CIB>());
Something2(new List<CIBD>());
Something2(bar.Cast<IA>());
// This call is illegal
Something2(bar);
return bar;
}
private static void Something2(IEnumerable<IA> foo)
{
}
}
我在Something2(bar)
行遇到错误:
参数1:无法从“ System.Collections.Generic.List”转换 到“ System.Collections.Generic.IEnumerable”
答案 0 :(得分:219)
该错误消息提供的信息不足,这是我的错。抱歉。
您遇到的问题是协方差仅适用于引用类型这一事实的结果。
您现在可能会说“但是IA
是引用类型”。是的。但是您没有说T
等于 IA
。您说T
是实现 IA
的类型,而值类型可以实现接口。因此,我们不知道协方差是否有效,因此我们不允许这样做。
如果要使用协方差,则必须告诉编译器类型参数是具有class
约束和IA
接口约束的引用类型。
错误消息确实应该说不可能进行转换,因为协方差需要保证引用类型,因为这是根本问题。
答案 1 :(得分:26)
对于那些不太熟悉通用约束的人,我只是想用一个代码示例来补充Eric的出色内幕答案。
按以下方式更改Something
的签名:class
约束必须排在第一位。
public static IList<T> Something<T>(IEnumerable<T> foo) where T : class, IA