ho letto l'articolo di Eric here circa foreach enumerazione e sui diversi scenari in cui foreach può funzionareC# `comportamento foreach` - Chiarimento?
Al fine di evitare che la vecchia C# versione di fare la boxe, il team di C# abilitato tipizzazione anatra per foreach per l'esecuzione su .. una collezione non IEnumerable (un pubblico GetEnumerator
che restituiscono qualcosa che ha pubblica MoveNext
e Current
proprietà è sufficiente (
Così, Eric ha scritto un sample:
class MyIntegers : IEnumerable
{
public class MyEnumerator : IEnumerator
{
private int index = 0;
object IEnumerator.Current { return this.Current; }
int Current { return index * index; }
public bool MoveNext()
{
if (index > 10) return false;
++index;
return true;
}
}
public MyEnumerator GetEnumerator() { return new MyEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
}
Ma credo che abbia alcuni errori di battitura (manca la funzione di accesso all'applicazione Current
) che impedisce la compilazione (l'ho già inviato via email).
Comunque qui è una versione funzionante:
class MyIntegers : IEnumerable
{
public class MyEnumerator : IEnumerator
{
private int index = 0;
public void Reset()
{
throw new NotImplementedException();
}
object IEnumerator.Current {
get { return this.Current; }
}
int Current {
get { return index*index; }
}
public bool MoveNext()
{
if (index > 10) return false;
++index;
return true;
}
}
public MyEnumerator GetEnumerator() { return new MyEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
}
Ok.
Secondo MSDN:
Un tipo
C
si dice che sia uncollection type
se implementa l'interfacciaSystem.Collections.IEnumerable
o attua lacollection pattern
incontrando tutti i seguenti criteri:
C contiene un metodo di istanza pubblico con la firma GetEnumerator() che restituisce un tipo di struttura, un tipo di classe o un tipo di interfaccia, che viene chiamato E nel seguente testo.
E contiene un metodo di istanza pubblico con la firma MoveNext() e il tipo restituito bool.
E contiene una proprietà di istanza pubblica denominata Current che consente di leggere il valore corrente. Si dice che il tipo di questa proprietà sia il tipo di elemento del tipo di raccolta.
OK. Diamo abbinare i documenti di campione di Eric
campione di Eric è detto di essere un collection type
perché fa implementa l'interfaccia System.Collections.IEnumerable
(esplicitamente però). Ma è non (!) a collection pattern
a causa di bullet 3: MyEnumerator
fa non proprietà di istanza pubblica denominata Current.
MSDN dice:
Se l'espressione di raccolta è di un tipo che implementa il pattern di raccolta (come definito sopra), l'espansione della dichiarazione foreach è:
E enumerator = (collection).GetEnumerator();
try {
while (enumerator.MoveNext()) {
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally {
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
Altrimenti, l'espressione di raccolta è di un tipo che implementa (!) S System.IEnumerable, e l'espansione della dichiarazione foreach è:
IEnumerator enumerator =
((System.Collections.IEnumerable)(collection)).GetEnumerator();
try {
while (enumerator.MoveNext()) {
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally {
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
Domanda # 1
Sembra che il campione di Eric né implementa il collection pattern
né System.IEnumerable
- quindi non è previsto che corrisponda a qualsiasi della condizione specificata sopra. Così come mai riesco ancora a scorrere via:
foreach (var element in (new MyIntegers() as IEnumerable))
{
Console.WriteLine(element);
}
Domanda # 2
Perché devo menzionare new MyIntegers() as IEnumerable
? è già IEnumerable (!!) e anche dopo questo, non è il compilatore sta già facendo il lavoro da sola via casting:
((System.Collections.IEnumerable)(collection)).GetEnumerator() ?
E 'proprio qui:
IEnumerator enumerator =
((System.Collections.IEnumerable)(collection)).GetEnumerator();
try {
while (enumerator.MoveNext()) {
...
Allora perché ancora vuole che menzioni come Ienumerable? o meglio, sarebbe se Current
erano pubbliche -
Ora sappiamo che la domanda riguarda principalmente l'errore di digitazione "System.Numerable", inoltre accennerò che questa specifica del linguaggio avrebbe dovuto consentire al campione di eseguire il cast senza ricorrere all'utilizzo dell'interfaccia 'IEnumerable'. La specifica non menziona mai un errore quando il modello di raccolta è parzialmente implementato (che è ciò che ho indicato nella mia risposta evidenziando la specifica C# 5.0 che spiega questo errore). – Lukazoid