Объекты определенного типа в foreach из IEnumerable - PullRequest
8 голосов
/ 23 августа 2011

Я работаю с устаревшим объектом коллекции, который реализует только неуниверсальные IEnumerable и ICollection.Что именно происходит с этим объектом, когда я пытаюсь использовать этот объект с foreach, дающим более конкретный тип в LHS выражения foreach?

// LegacyFooCollection implements non-generic IEnumerable
LegacyFooCollection collection = GetFooCollection();
foreach (Foo f in collection)
{
    // etc.
}

Я знаю (потому что я пробовал это)что это безопасно, когда все в collection действительно имеет тип Foo, но что произойдет, если это не удастся?

Ответы [ 4 ]

14 голосов
/ 23 августа 2011

Компилятор C # выполняет приведение неявно для вас. С точки зрения каста (но только в этих терминах 1 ) это эквивалентно:

foreach (object tmp in collection)
{
    Foo f = (Foo) tmp;
    ...
}

Обратите внимание, что это произойдет и с общими коллекциями:

List<object> list = new List<object> { "hello", "there", 12345 };

// This will go bang on the last element
foreach (string x in list) 
{
}

Все это подробно описано в разделе 8.8.4 спецификации C # 4.

Если вы используете .NET 3.5 или выше и хотите выбрать только элементы соответствующего типа, вы можете использовать Enumerable.OfType:

LegacyFooCollection collection = GetFooCollection();
foreach (Foo f in collection.OfType<Foo>())
{
    // etc.
}

Это может быть необязательно для LegacyFooCollection, но может быть полезно, когда вы пытаетесь найти (скажем) все TextBox элементы управления в форме.


1 Различия:

  • В исходном коде f только для чтения; в «конверсии» это доступно для записи
  • В исходном коде, если вы захватите f, вы (в настоящее время) захватите одну переменную на всех итерациях, в отличие от отдельной переменной на каждую итерацию в «преобразовании»
3 голосов
/ 23 августа 2011

Этот код создаст во время выполнения преобразование типов (приведение) каждого элемента из перечисляемого в Foo.Итак, если вы сделали foreach (string f in collection), вы получите ClassCastException во время выполнения, когда он впервые попытается преобразовать ссылку Foo в ссылку String.

0 голосов
/ 19 мая 2015

Шорт в ForEeach:

foreach (MenuItem menuItem in treeView.ContextMenu.Items.Cast<object>().OfType<MenuItem>()
{
    // Do stuff
}
0 голосов
/ 23 августа 2011

Это будет кастинг каждый раз. Цикл foreach использует только методы IEnumerator.

...