Як я розумію, ваше запитання базується на неправильній передумові. Дозвольте мені побачити, чи можу я відновити міркування:
- Стаття, що пов'язана з описом, описує, як автоматично генеровані послідовності виявляють "ледачу" поведінку, і показує, як це може призвести до контрінтуїтивного результату.
- Тому я можу виявити, чи збирається даний екземпляр 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>
.