IEnumerable - как непустая коллекция может быть пустой одновременно? - PullRequest
4 голосов
/ 02 сентября 2010

Я не могу понять это. Рабочий процесс передачи IEnumerable (T это мой класс, но здесь он не актуален) в основном выглядит так:

var a = GetEntireCollection(); // so I get IEnumerable<T>
...
var b = a.Where(condition1);
...
var c = b.Where(condition2);
...

Поэтому я отфильтровываю все больше и больше предметов из коллекции, наконец, я звоню:

if (z.IsEmpty())
    throw new Exception();
Foo(z);

и Foo

public void Foo(IEnumerable<T> p)
{
    pool = p.OrderByDescending(it => it.MyProperty).ToList();

    if (pool.IsEmpty())
        throw new Exception(pool.Count().ToString() + ", " + p.Count().ToString());
    ...

Все, что я делаю, это заказ коллекции.

Теперь моя программа аварийно завершает работу - она ​​говорит, что p имеет Count = 1, а пул имеет Count = 0. Более того, когда я указываю p и требую результатов (я запускаю программу с использованием Visual Studio), он говорит коллекция дала безрезультатно (или что-то похожее, не дословно).

Вопросы:

  1. как непустая коллекция может стать пустой только при переупорядочении?
  2. как счетчик коллекции может быть> 0, если в нем нет элементов?

Я спрашиваю, потому что я хотел бы знать, как избежать этой ситуации, но, честно говоря, когда я смотрю на код, он кажется мне на 100% законным.

Техническая информация :

  • это чистый код C #, никаких встроенных ассемблеров или что-то в этом роде
  • без темы
  • никаких внешних библиотек, кроме Where (которое происходит от Linq), это весь мой код

Редактирование

Редактировать 1

public static bool IsEmpty<T>(this IEnumerable<T> coll)
{
    var iter = coll.GetEnumerator();
    return !iter.MoveNext();
}

Редактировать 2

Непосредственно перед тем, как я вызываю Foo (z), я проверяю, является ли z пустым, поэтому код выглядит так:

if (z.IsEmpty())
    throw new Exception();
Foo(z);

решаемые * +1051 * Как предположил Джон (я бы сказал, C # sharpshooting), одно из условий зависело от времени. Поэтому, когда оценка коллекции была принудительной, условие изменилось, и я получил другую коллекцию.

Ответы [ 3 ]

3 голосов
/ 02 сентября 2010

Одна возможность состоит в том, что оценка условий дважды приводит к эффективному изменению результатов.

Каждый раз, когда вы выполняете итерацию по p, он будет переоценивать данные, включая предложения Where.Таким образом, вы делаете это один раз, чтобы заполнить pool, а затем снова распечатать p.Count().

Без дополнительной информации о том, что делает GetEntireCollection или каковы условия Where, это трудносказать, что происходит ... но это одно из возможных объяснений.Если вы можете опубликовать короткую, но полную программу, демонстрирующую проблему, это очень поможет.

1 голос
/ 02 сентября 2010

Пусто из-за Отложенное выполнение , большинство операторов запросов выполняются не тогда, когда построено, но при перечислении (другими словами, когда MoveNext вызывается на его переписчик).

Так что если вы измените его на:

var c = b.Where(condition2).ToList(); 

А затем вызовите Foo (c), это сработает.

0 голосов
/ 02 сентября 2010

Я думаю, что код, который вы показываете, будет вызывать GetEntireCollection несколько раз.

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

...