La tua domanda, a quanto ho capito, sembra essere basata su una premessa errata. Fammi vedere se riesco a ricostruire il ragionamento:
- L'articolo collegato a descrive come le sequenze generate automaticamente mostrano un comportamento "pigro" e mostra come ciò può portare a un risultato contro-intuitivo.
- Pertanto posso rilevare se una determinata istanza di IEnumerable mostrerà questo comportamento pigro verificando se viene generata automaticamente.
- Come lo faccio?
Il problema è che la seconda premessa è falsa. Anche se fosse in grado di rilevare se un determinato IEnumerable fosse o meno il risultato di una trasformazione del blocco iteratore (e sì, ci sono modi per farlo) non sarebbe utile perché l'ipotesi è errata. Illustriamo il perché.
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;
}
}
Bene, abbiamo quattro metodi. S1 e S2 sono sequenze generate automaticamente; S3 e S4 sono sequenze generate manualmente. Supponiamo ora di avere:
var items = C.Sn(); // S1, S2, S3, S4
S.Add100(items);
Console.WriteLine(items.First().P);
Il risultato per S1 e S4 sarà 0; ogni volta che si enumera la sequenza, si ottiene un nuovo riferimento a una M creata. Il risultato per S2 e S3 sarà 100; ogni volta che si enumera la sequenza, si ottiene lo stesso riferimento a M ottenuto l'ultima volta. Se il codice di sequenza viene generato automaticamente o meno è ortogonale alla domanda se gli oggetti elencati abbiano o meno identità referenziale. Queste due proprietà - generazione automatica e identità referenziale - in realtà non hanno nulla a che fare l'una con l'altra. L'articolo che hai collegato li confonde in qualche modo.
A meno che un provider di sequenze non sia documentato come fornisca sempre oggetti con identità referenziale , non è saggio supporre che lo faccia.
ICollection<T>
sarebbe una scelta migliore in quanto non tutte le collezioni lo sonoList<T>
. Ad esempio, le matriciPoint[]
implementanoIList<T>
ma non lo sonoList<T>
.