【问题标题】:Warning - does not implement the 'collection' pattern警告 - 不实现“收集”模式
【发布时间】:2017-08-15 12:34:12
【问题描述】:

我正在收集,明确实现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' 没有实现 'collection' 模式。 'MyCollection.GetEnumerator()' 要么是静态的,要么是非公开的。

是的,它不公开。为什么应该这样?我可以将其公开,但类型以外的foreach 不需要:

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

我做错了吗?

【问题讨论】:

  • 就叫别的吧? GetEnumeratorImpl?或者只是不要为IEnumerable&lt;T&gt;.GetEnumerator?使用显式接口实现
  • @JonSkeet,所以它只是名称 confising 编译器?
  • 是的 - 因为foreach 中的模式匹配找到 GetEnumerator() 方法,但不能使用它。现在添加答案...

标签: c# foreach ienumerable compiler-warnings


【解决方案1】:

存在警告是因为 C# 编译器可以通过多种不同方式处理 foreach。其中一种方法是找到具有合适返回类型的GetEnumerator 方法。这是在编译器检查表达式的类型是否实现IEnumerableIEnumerable&lt;T&gt; 之前检查的。

在您的情况下,它可以找到单个无参数 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&lt;T&gt;.GetEnumerator() 使用显式接口实现 - 将实现放在那里

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    public IEnumerator<T> GetEnumerator() => { yield return default(T); }
    
  • 将实现放在IEnumerable&lt;T&gt;.GetEnumerator 中,但将this 转换为IEnumerable&lt;T&gt;IEnumerable.GetEnumerator 中调用它:

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

【讨论】:

  • 第二个选项是我认为最干净的。我明显的错误是显式地实现了这两个接口,只需要一个。谢谢。
【解决方案2】:

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

C# 中有几个语句依赖于定义的模式,例如 作为 foreach 和使用。例如,foreach 依赖于集合 实现可枚举模式的类。发生此错误时 由于声明了方法,编译器无法进行匹配 静态或不公开。 模式中的方法必须是实例 类,并公开

(强调我的)

【讨论】:

  • 不是重点。阅读explicit 接口实现。外部foreach 不需要任何显式方法即可公开。事实上,您不能公开显式实现
猜你喜欢
  • 2013-04-10
  • 2021-12-11
  • 1970-01-01
  • 2018-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多