Ваш вопрос, насколько я понимаю, кажется, основан на неверной предпосылке. Позвольте мне посмотреть, смогу ли я восстановить аргументацию:
- Связанная статья описывает, как автоматически сгенерированные последовательности демонстрируют «ленивое» поведение, и показывает, как это может привести к противоречивому результату.
- Поэтому я могу определить, будет ли данный экземпляр IEnumerable демонстрировать это ленивое поведение, проверив, генерируется ли он автоматически.
- Как мне это сделать?
Проблема в том, что вторая предпосылка неверна. Даже если бы вы могли определить, был ли данный IEnumerable результатом преобразования блока итератора (и да, есть способы сделать это), это не помогло бы, потому что предположение неверно. Давайте проиллюстрируем почему.
class M { public int P { get; set; } }
class C
{
public static IEnumerable<M> S1()
{
for (int i = 0; i < 3; ++i)
yield return new M { P = i };
}
private static M[] ems = new M[]
{ new M { P = 0 }, new M { P = 1 }, new M { P = 2 } };
public static IEnumerable<M> S2()
{
for (int i = 0; i < 3; ++i)
yield return ems[i];
}
public static IEnumerable<M> S3()
{
return new M[]
{ new M { P = 0 }, new M { P = 1 }, new M { P = 2 } };
}
private class X : IEnumerable<M>
{
public IEnumerator<X> GetEnumerator()
{
return new XEnum();
}
// Omitted: non generic version
private class XEnum : IEnumerator<X>
{
int i = 0;
M current;
public bool MoveNext()
{
current = new M() { P = i; }
i += 1;
return true;
}
public M Current { get { return current; } }
// Omitted: other stuff.
}
}
public static IEnumerable<M> S4()
{
return new X();
}
public static void Add100(IEnumerable<M> items)
{
foreach(M item in items) item.P += 100;
}
}
Хорошо, у нас есть четыре метода. S1 и S2 - автоматически генерируемые последовательности; S3 и S4 - сгенерированные вручную последовательности. Теперь предположим, что у нас есть:
var items = C.Sn(); // S1, S2, S3, S4
S.Add100(items);
Console.WriteLine(items.First().P);
Результат для S1 и S4 будет 0; каждый раз, когда вы перечисляете последовательность, вы получаете новую ссылку на созданную букву M. Результат для S2 и S3 будет 100; каждый раз, когда вы перечисляете последовательность, вы получаете ту же ссылку на M, что и в прошлый раз. То, генерируется ли код последовательности автоматически или нет, является ортогональным к вопросу о том, имеют ли перечисленные объекты ссылочную идентичность или нет. Эти два свойства - автоматическая генерация и ссылочная идентичность - на самом деле не имеют ничего общего друг с другом. Статья, на которую вы ссылаетесь, несколько их объединяет.
Если поставщик последовательности не задокументирован как всегда предлагающий объекты, имеющие ссылочную идентичность , неразумно полагать, что это так.
ICollection<T>
это был бы лучший выбор, поскольку не все коллекцииList<T>
. Например, массивыPoint[]
реализуют,IList<T>
но это не такList<T>
.