我不明白为什么编译器无法解决在这里使用的正确重载。 (下面的代码)只有一个版本的Add()是合适的--BigFoo是一个IFoo,并且没有实现IEnumerable,其中T是一个IFoo。但它坚持报道模棱两可。有任何想法吗?我尝试添加第二个泛型类型参数 - 添加其中T:IFoo其中U:IEnumerable。但即使合法使用,过载也完全被忽略。
我知道我可以通过强制转换和指定泛型类型参数解决这个问题,但那时我已经打败了过载的目的。你可以质疑重载,但语义对我来说是正确的 - 我在我的类中实现的行为是Add()将对象批量添加为集合中的单个条目。 (第二个Add()不应该是AddRange()。)
namespace NS
{
interface IFoo { }
class BigFoo : IFoo, IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
class FooContainer
{
public void Add(IFoo item) { }
public void Add<T>(IEnumerable<T> group) where T : IFoo { }
}
class DemoClass
{
void DemoMethod()
{
BigFoo bigFoo = new BigFoo();
FooContainer fooContainer = new FooContainer();
// error CS0121: The call is ambiguous between the following methods or properties:
// 'NS.FooContainer.Add(NS.IFoo)' and
// 'NS.FooContainer.Add<int>(System.Collections.Generic.IEnumerable<int>)'
fooContainer.Add(bigFoo);
}
}
}
答案 0 :(得分:6)
通用重载解析不考虑约束,因此它认为Add<T>
版本适用,推断T=int
。
这两种方法都适用,并且两种方法都不比其他方法更好,因为IEnumerable<int>
和IFoo
之间没有转换。虽然泛型方法被认为比非泛型方法“更不具体”,但只有在类型参数替换后参数类型相同时才会变得相关,在这种情况下它们不是。
答案 1 :(得分:1)
在FooContainer中,在第二个“添加”上,您将T限制为IFoo类型。 BigFoo实现了IFoo接口,因此它与Add定义匹配(即使它没有真正,因为它没有实现IEnumable&lt; IFoo&gt;)。
我不确定我完全理解你想要什么,但我怀疑是这样:
public void Add<T>(T group) where T : IEnumerable<IFoo> { }
允许你添加任何对象T,其中T是一组可枚举的IFoo对象。
这就是你想要的吗?
此致 理查德
答案 2 :(得分:0)
编译器应该足够聪明,能够识别BigFoo
无法转换为IEnumerable<IFoo>
,但事实并非如此。它只是看到它是IEnumerable<T>
,并认为它是一个潜在的超载候选者(即使您定义的约束强制执行T
必须IFoo
而int
不能被投到IFoo
)。虽然不方便,但这并不是什么大不了的事。只需将bigFoo转换为IFoo
,编译器就会很高兴:
fooContainer.Add((IFoo)bigFoo);
或者,您可以进行Add uglier:
的泛型重载public void Add<T, U>(U group)
where T : IFoo
where U : IEnumerable<T>
{
}
无论哪种方式,你有更多的输入,第二个解决方案消除了对Add
的调用的需要,但你必须显式声明对泛型add的调用类型(最终会有更多代码:< / p>
fooContainer.Add<IFoo, IEnumerable<IFoo>>(enumerableFoo);
答案 3 :(得分:0)
这里的问题是泛型类型约束被编译器完全忽略(它只查看参数类型)。就编译器而言,传递的IEnumerable<T>
参数也可以是IEnumerable<IFoo>
。
有关此主题的完整信息,请参阅{{3>}的 25.6.4类型参数推断部分。请注意,没有提及类型约束的使用。
答案 4 :(得分:0)
有趣......只是尝试了你的样品。仿制药继续让我保持警惕。
//1 - First preference
public void Add(BigFoo item) { Console.WriteLine("static BigFoo type Add"); }
//2 - Second Preference
public void Add<T>(T item) { Console.WriteLine("Generic Add"); }
//3 - Third preferences
public void Add(IFoo item) { Console.WriteLine("static IFoo interface Add"); }
//4 - Compiles if 1-4 exist. Compile error (ambiguity) if only 3-4 exist. Compile error (cannot convert int to IFoo) if only 4 exists
public void Add<T>(IEnumerable<T> group) where T : IFoo { }