【问题标题】:Implementing IEnumerable with an Array用数组实现 IEnumerable
【发布时间】:2012-07-03 20:35:15
【问题描述】:

这可能是一个简单的语法问题,但我想不通。

通常,我会这样做:

public class OrderBook : IEnumerable<PriceLevel>
{
    private readonly List<PriceLevel> PriceLevels = new List<PriceLevel>();

    public IEnumerator<PriceLevel> GetEnumerator()
    {
        return PriceLevels.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return PriceLevels.GetEnumerator();
    }
}

但我想使用数组而不是列表 - 像这样:

public class ArrayOrderBook : IEnumerable<PriceLevel>
{
    private PriceLevel[] PriceLevels = new PriceLevel[500];

    public IEnumerator<PriceLevel> GetEnumerator()
    {
        return PriceLevels.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return PriceLevels.GetEnumerator();
    }
}

IEnumerator IEnumerable.GetEnumerator() 似乎编译得很好 - 但公众 IEnumerator&lt;PriceLevel&gt; 说我需要某种类型的演员 - 最好的方法是什么?

威廉

【问题讨论】:

  • 为什么?为什么要为此使用数组?
  • List 由数组本身支持,因此除了工作过于复杂之外,您不会获得任何好处。
  • @Tudor 取决于类中的其他逻辑,PriceLevels 可能更有意义成为一个数组(例如固定大小)。想要重构它没有错。
  • 是的 - 这是对更大和长话短说它需要是一个数组的严重过度简化(至少现在是这样)

标签: c# ienumerable


【解决方案1】:

试试这个:

public class ArrayOrderBook : IEnumerable<PriceLevel>
{
    private PriceLevel[] PriceLevels = new PriceLevel[500];

    public IEnumerator<PriceLevel> GetEnumerator()
    {
        return PriceLevels.AsEnumerable().GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return PriceLevels.GetEnumerator();
    }
}

【讨论】:

  • 可以推断类型。 .AsEnumerable() 工作得很好。 T[] 实现了IEnumerable&lt;T&gt;,但它的GetEnumerator 的公共方法返回一个弱类型的IEnumerator
【解决方案2】:

从您自己的IEnumerable&lt;T&gt; 实现中可以看出,您需要提供通用和非通用版本的方法来实现接口。为了做到这一点,由于这些方法具有相同的签名,因此其中之一需要是显式接口实现。对于List,泛型版本是类中的方法,非泛型版本是显式接口定义,因为泛型版本通常更有用。在数组的情况下,它已经有非泛型版本作为实现,并且在后续版本中添加了该方法的泛型版本。为了避免重大更改,通用版本改为显式接口定义。

有多种方法可以解决此问题。以下是三个简单的。

public IEnumerator<PriceLevel> GetEnumerator()
{
    return PriceLevels.AsEnumerable().GetEnumerator();
}


public IEnumerator<PriceLevel> GetEnumerator()
{
    IEnumerable<PriceLevel> enumerator = PriceLevels;
    return enumerator.GetEnumerator();
}

public IEnumerator<PriceLevel> GetEnumerator()
{
    return ((IEnumerable<PriceLevel>)PriceLevels).GetEnumerator()
}

【讨论】:

    【解决方案3】:

    T[] 转换为对应的IEnumerable&lt;T&gt;

        public IEnumerator<PriceLevel> GetEnumerator()
        {
            return ((IEnumerable<PriceLevel>)PriceLevels).GetEnumerator();
        }
    

    【讨论】:

      【解决方案4】:

      根据 ECMA-335 Partition I, §8.9.1,向量类型(单维数组,如 T[])实现了 IList&lt;T&gt;,这意味着它也实现了 IEnumerable&lt;T&gt;。但是,这些方法的实现是明确的,因此您需要使用其中之一:

      选项 1:简单地使用数组的隐式分配给IList&lt;T&gt;

      private IList<PriceLevel> PriceLevels = new PriceLevel[500];
      

      选项2:将成员变量保留为数组,并使用AsEnumerable 扩展方法。此扩展方法使用受支持的隐式赋值,这比使用像 (IEnumerable&lt;PriceLevel&gt;)PriceLevels 这样的直接转换更可取。

      IEnumerator IEnumerable.GetEnumerator()  
      {  
          return PriceLevels.AsEnumerable().GetEnumerator();  
      }  
      

      要避免的项目:

      1. Cast&lt;T&gt; 方法为数组的每个元素引入了不必要的类型检查,应避免使用。
      2. 如果只需要在枚举中包含非空元素,可以使用OfType&lt;T&gt;扩展方法。否则,此方法还会对每个元素进行不必要的类型检查。

      【讨论】:

        猜你喜欢
        • 2014-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-15
        • 1970-01-01
        • 1970-01-01
        • 2010-09-21
        相关资源
        最近更新 更多