Реализация IEnumerable с помощью массива

Это, скорее всего, простой синтаксический вопрос, но я не могу понять.

Обычно я бы сделал это:

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() компилируется отлично, но public IEnumerator<PriceLevel> говорит, что мне нужен какой-то актерский состав - что это лучший способ сделать это?

Уильям

Ответ 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();
    }
}

Ответ 2

Как вы можете видеть из своей собственной реализации IEnumerable<T>, вам необходимо предоставить как общую, так и не общую версию метода для выполнения интерфейса. Для этого, поскольку методы имеют одну и ту же подпись, одна из них должна быть явной реализацией интерфейса. В случае 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<T>:

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

Ответ 4

В соответствии с разделом I.88.1 раздела ECMA-335 векторный тип (одномерный массив, такой как T[]) реализует IList<T>, что подразумевает, что он также реализует IEnumerable<T>. Однако реализация методов является явной, поэтому вам нужно будет использовать один из них:

Вариант 1: просто используйте неявное назначение массивов на IList<T>.

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

Вариант 2. Оставьте переменную-член как массив и используйте метод расширения AsEnumerable. Этот метод расширения использует поддерживаемое неявное присвоение, которое предпочтительнее использования прямого приведения типа (IEnumerable<PriceLevel>)PriceLevels.

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

Элементы, которые следует избегать:

  • Метод Cast<T> вводит ненужную проверку типа для каждого элемента вашего массива и его следует избегать.
  • Если вам нужно включить только ненулевые элементы из перечисления, используйте OK для использования метода расширения OfType<T>. В противном случае этот метод также вводит ненужную проверку типов для каждого элемента.