我正在进行收集,明确地实现IEnumerable
并尝试从内部迭代它:
public class MyCollection<T> : IEnumerable<T>, IEnumerable
{
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
IEnumerator<T> GetEnumerator() { yield return default(T); } // test
public void Test()
{
foreach (var item in this) { } // here is warning
}
}
我在this
收到编译器警告:
警告CS0279'MyCollection'未实现'集合'模式。 'MyCollection.GetEnumerator()'是静态的还是不公开的。
天哪,它不公开。为什么会这样?我可以将其公开,但foreach
类型之外不需要它:
foreach (var item in new MyCollection<string>()) { } // no warning
我做错了吗?
答案 0 :(得分:4)
警告存在是因为C#编译器可以通过多种不同方式处理foreach
。其中一种方法是找到具有合适返回类型的GetEnumerator
方法。在之前检查,编译器检查表达式的类型是否实现IEnumerable
或IEnumerable<T>
。
在您的情况下,它可以找到单个无参数GetEnumerator
方法,但它不公开。此时C#规范建议发出警告,因为您可能打算它可用于foreach
。从C#5规范,第8.8.4节,强调我的:
- 使用生成的方法组和空参数列表执行重载解析。如果重载决策导致没有适用的方法,导致歧义,或导致单个最佳方法但该方法是静态的或不公开的,请检查可枚举的接口,如下所述。 如果重载决策产生除明确的公共实例方法或没有适用的方法之外的任何内容,建议发出警告。
以下任何一种方法都可以解决问题:
将GetEnumerator
重命名为GetEnumeratorImpl
或类似名称:
IEnumerator IEnumerable.GetEnumerator() => GetEnumeratorImpl();
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumeratorImpl();
IEnumerator<T> GetEnumeratorImpl() { yield return default(T); }
不要对IEnumerable<T>.GetEnumerator()
使用显式接口实现 - 将实现放在那里
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<T> GetEnumerator() => { yield return default(T); }
将实施放在IEnumerable<T>.GetEnumerator
中,但将this
投放到IEnumerable<T>
中的IEnumerable.GetEnumerator
进行调用:
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<T>) this).GetEnumerator();
IEnumerator<T> IEnumerable<T>.GetEnumerator() => { yield return default(T); }
答案 1 :(得分:2)
请在此处查看编译器警告CS0279的说明:https://msdn.microsoft.com/en-us/library/bz2286x8(v=vs.90).aspx
C#中有几个依赖于定义模式的语句,例如 作为foreach 并使用。例如, foreach依赖于集合 实现可枚举模式的类。当发生此错误 由于声明了方法,编译器无法进行匹配 静态或不公开。 模式中的方法必须是实例 课程,并公开。
(强调我的)