ForEach, дающий Invalid Cast во время выполнения - PullRequest
3 голосов
/ 18 февраля 2011

У меня есть следующее:

 foreach (ItemOption itemOption in p.Items.Select(e => e.ItemOption).GroupBy(e => e.Id))
  { // do some work on itemoptions }

Это компилируется. Однако во время выполнения я получаю исключение Invalid Cast:

Невозможно привести объект типа «Группировка [System.String, MyNameSpace.ItemOption]» к типу «MyNameSpace.ItemOption».

Если я изменю код, например, на Строка как тип элемента:

 foreach (String itemOption in p.Items.Select(e => e.ItemOption).GroupBy(e => e.Id))
  { // do some work on itemoptions }

Тогда компилятор сообщает мне, что типы несовместимы.

Почему компилятор не помечает несовместимость типов в первом блоке кода?


Я провел дополнительное расследование и обнаружил, что, учитывая следующий код:

var foo = p.Items.Select(e => e.ItemOption).GroupBy(e => e.Id));
Type singleElementType = foo.ElementAt(0).GetType();

singleElementType:

System.Linq.Lookup`2 + Группировка [System.String, MyNamespace.ItemOption]


UPDATE Исходя из ответов, я собрал более простой пример, чтобы продемонстрировать проблему

Учитывая объекты:

interface IMyObj
{
    string Id;
}

class MyObj : IMyObj
{
    public string Id;
    public MyObj2 cg;
}

class MyObj2
{
}

Это не удастся во время компиляции

IEnumerable<MyObj> compileTimeFailList = new List<MyObj>()
foreach (MyObj2 myObj2 in compileTimeFailList.Where(x => x.Id != null))
{

и произойдет сбой во время выполнения

IEnumerable<IMyObj> runtimeFailList = new List<IMyObj>();
foreach (MyObj2 myObj2 in runtimeFailList.Where(x => x.Id != null))
{ 

Причина в том, что объекты в runtimeFailList могут расширять MyObj2, и компилятор не может определить это.

Ответы [ 3 ]

3 голосов
/ 18 февраля 2011

ItemOption предположительно не является закрытым классом (в отличие от System.String), поэтому возможно, что результатом p.Items.Select(...).GroupBy(...) будут реализации IGrouping<...>, которые были также ItemOption значениями. Компилятор не может знать, поэтому он вставляет неявное приведение. Поскольку string не реализует IGrouping<...> и запечатан, компилятор может обнаружить, что это определенно ошибка.

foreach имеет всегда , включая актерский состав, где это необходимо. Это немного противно, потому что оно скрыто ... но без него foreach было бы очень больно использовать пре-дженерики.

Теперь о том, почему это на самом деле неправильно ... каждый элемент в результате будет группой, а не отдельным элементом. Дайте мне знать, если вам нужна дополнительная помощь в работе с результатами.

1 голос
/ 18 февраля 2011

Это потому, что класс String не может быть унаследован, но ваш класс ItemOption может быть унаследован и также может быть неявно приведен.

0 голосов
/ 18 февраля 2011

О том, почему происходит сбой приведения:

foreach (ItemOption itemOption in p.Items.Select(e => e.ItemOption).GroupBy(e => e.Id))

Ваш .GroupBy не возвращает список ItemOptions, сгруппированных по id.Скорее он возвращает список списков: первый список содержит все отдельные Id с, и для каждого идентификатора есть список ItemOption с тем же идентификатором.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...