Den*_*nis 5 c# generics overload-resolution
代码示例:
interface IFoo { }
class FooImpl : IFoo { }
static void Bar<T>(IEnumerable<T> value)
where T : IFoo
{
}
static void Bar<T>(T source)
where T : IFoo
{
}
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释,为什么这个方法调用:
var value = new FooImpl[0];
Bar(value);
Run Code Online (Sandbox Code Playgroud)
目标Bar<T>(T source)(因此,不编译)?
在解决重载时,编译器是否会考虑类型参数约束?
UPD.
避免与数组混淆.任何实现都会发生这种情况IEnumerable<T>,例如:
var value = new List<FooImpl>();
Run Code Online (Sandbox Code Playgroud)
UPD 2.
@ ken2k提到了协方差.但是,让我们忘掉FooImpl.这个:
var value = new List<IFoo>();
Bar(value);
Run Code Online (Sandbox Code Playgroud)
产生相同的错误.
我敢肯定,之间的隐式转换List<IFoo>和IEnumerable<IFoo>存在,因为我可以很容易地写出这样的事情:
static void SomeMethod(IEnumerable<IFoo> sequence) {}
Run Code Online (Sandbox Code Playgroud)
并传入value其中:
SomeMethod(value);
Run Code Online (Sandbox Code Playgroud)
在解决重载时,编译器是否完全考虑类型参数约束?
不,因为通用约束不是函数签名的一部分。您可以通过添加除Bar通用约束之外相同的重载来验证这一点:
interface IBar { }
static void Bar<T>(IEnumerable<T> value)
where T : IFoo
{
}
static void Bar<T>(T source)
where T : IBar
{
// fails to compile : Type ____ already defines a member called 'Bar' with the same parameter types
}
Run Code Online (Sandbox Code Playgroud)
您的代码无法编译的原因是编译器根据方法签名选择“最佳”匹配,然后尝试应用通用约束。
不这样做的一个可能原因是这个调用不明确:
{假设List<T>有一个Add<T>(IEnumerable<T> source) 方法}
List<object> junk = new List<object>();
junk.Add(1); // OK
junk.Add("xyzzy") // OK
junk.Add(new [] {1, 2, 3, 4}); //ambiguous - do you intend to add the _array_ or the _contents_ of the array?
Run Code Online (Sandbox Code Playgroud)
明显的解决方法是对采用集合的方法使用不同的名称Bar(就像在 BCL 中使用Addand所做的那样AddRange)。