.NET Framework 4.8中实现双接口后编译器为何无法识别IEnumerable<T>?
在.NET Framework 4.8中定义了同时实现IEnumerable<Bar>和IReadOnlyDictionary<int, Bar>的类:
public class Foo : IEnumerable<Bar>, IReadOnlyDictionary<int, Bar> { public Bar this[int key] => /* ... */; public IEnumerable<int> Keys => /* ... */; public IEnumerable<Bar> Values => /* ... */; public int Count => /* ... */; public bool ContainsKey(int key) => /* ... */; public IEnumerator<Bar> GetEnumerator() => /* ... */; public bool TryGetValue(int key, out Bar value) => /* ... */; IEnumerator IEnumerable.GetEnumerator() { /* ... */; } IEnumerator<KeyValuePair<int, Bar>> IEnumerable<KeyValuePair<int, Bar>>.GetEnumerator() { /* ... */; } }
使用foreach循环遍历该类实例可正常运行:
var foo = new Foo(); foreach (var bar in foo) { /* ... */ }
但调用IEnumerable<T>的扩展方法(如Any())时:
bool b = foo.Any();
出现错误:
CS1061 'Foo' does not contain a definition for 'Any' and no accessible extension method 'Any' accepting a first argument of type 'Foo' could be found (are you missing a using directive or an assembly reference?)
已包含using System.Linq;语句,移除IReadOnlyDictionary<int, Bar>接口后错误消失,请问为何同时实现两个接口时编译器无法识别IEnumerable<T>?
这是因为**IReadOnlyDictionary<TKey, TValue>本身继承了IEnumerable<KeyValuePair<TKey, TValue>>**,你的Foo类同时实现了IEnumerable<Bar>和IEnumerable<KeyValuePair<int, Bar>>(通过IReadOnlyDictionary),导致编译器无法确定应该将Foo实例绑定到哪个泛型版本的IEnumerable<T>扩展方法。
Linq的扩展方法(如Any())是定义在Enumerable类中的泛型方法,当类型实现多个IEnumerable<T>接口时,编译器无法自动推断出正确的T类型,因此找不到匹配的扩展方法。
而foreach循环可以正常工作,是因为foreach会优先使用类中显式实现的GetEnumerator()方法(即你定义的IEnumerator<Bar> GetEnumerator()),不需要编译器进行泛型类型推断。
有三种常见的解决方式:
- 显式指定泛型类型参数:调用扩展方法时明确告诉编译器使用
IEnumerable<Bar>版本:bool b = foo.Any<Bar>(); - 显式转换为
IEnumerable<Bar>:将实例强制转换为目标接口后再调用方法:bool b = ((IEnumerable<Bar>)foo).Any(); - 添加返回
IEnumerable<Bar>的方法:在Foo类中新增一个方法明确暴露目标接口:
之后调用:public IEnumerable<Bar> AsEnumerable() => this;bool b = foo.AsEnumerable().Any();
内容的提问来源于stack exchange,提问作者Bill Tűr stands with Ukraine

