警告 - 未实现 'collection' 模式

Warning - does not implement the 'collection' pattern

我正在收集,明确实施 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 收到编译器警告:

Warning CS0279 'MyCollection' does not implement the 'collection' pattern. 'MyCollection.GetEnumerator()' is either static or not public.

天哪,这不是 public。为什么会这样?我 可以 使它成为 public,但对于 foreach 类型之外的类型不需要它:

foreach (var item in new MyCollection<string>()) { } // no warning

我是不是做错了什么?

在此处查看编译器警告 CS0279 的解释:https://msdn.microsoft.com/en-us/library/bz2286x8(v=vs.90).aspx

There are several statements in C# that rely on defined patterns, such as foreach and using. For example, foreach relies on the collection class implementing the enumerable pattern. This error occurs when the compiler is unable to make the match due to a method being declared static or not public. Methods in patterns are required to be instances of classes, and to be public.

(强调我的)

存在警告是因为 C# 编译器可以用多种不同的方式处理 foreach。其中一种方法是找到具有合适 return 类型的 GetEnumerator 方法。在 之前 编译器检查表达式的类型是否实现 IEnumerableIEnumerable<T>.

在你的例子中,它找到了单一的无参数 GetEnumerator 方法,但它不是 public。 C# 规范建议此时发出警告,因为您可能 打算 它可用于 foreach。来自 C# 5 规范,第 8.8.4 节,强调我的:

  • Perform overload resolution using the resulting method group and an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for an enumerable interface as described below. It is recommended that a warning be issued if overload resolution produces anything except an unambiguous public instance method or no applicable methods.

以下任何一项都可以解决问题:

  • 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 中,但在 IEnumerable.GetEnumerator 中将 this 转换为 IEnumerable<T> 以调用它:

    IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<T>) this).GetEnumerator();
    IEnumerator<T> IEnumerable<T>.GetEnumerator() => { yield return default(T); }