Реализация 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>
. В противном случае этот метод также вводит ненужную проверку типов для каждого элемента.