Fondamentalmente le interfacce non generiche sono arrivate per prime, in .NET 1.0 e 1.1. Poi, quando è uscito .NET 2.0, sono usciti gli equivalenti generici. La vita sarebbe stata molto più semplice se i farmaci generici avevano fatto in .NET 1.0 :)
In termini di attuazione di "solo" IEnumerable<T>
invece di due - che, fondamentalmente, hanno per implementare entrambi, e si deve usare l'interfaccia esplicita anche l'implementazione, dato che entrambi definiscono un metodo senza parametro GetEnumerator
. Come IEnumerator<T>
estende IEnumerator
troppo, è di solito qualcosa di simile:
public IEnumerator<T> GetEnumerator()
{
// Return real iterator
}
// Explicit implementation of nongeneric interface
IEnumerator IEnumerable.GetEnumerator()
{
// Delegate to the generic implementation
return GetEnumerator();
}
D'altra parte, con i blocchi iteratore introdotte in C# 2 (con yield return
ecc) che raramente necessario implementare queste cose interamente a mano, per fortuna. Potrebbe essere necessario scrivere qualcosa come sopra, e quindi utilizzare yield return
nel metodo GetEnumerator
.
Nota che IList<T>
fa non estendono IList
, e ICollection<T>
fa non estendono ICollection
. Questo perché è meno sicuro del tipo farlo ... mentre qualsiasi iteratore generico può essere visto come un iteratore non generico a causa della conversione (potenzialmente in box) di qualsiasi valore in object
, IList
e ICollection
consentire valori da aggiunto al collezione; e non ha senso aggiungere (ad esempio) una stringa a IList<int>
.
MODIFICA: Il motivo per cui abbiamo bisogno di IEnumerable<T>
è che possiamo eseguire iterazioni in modo sicuro e propagare tali informazioni. Se restituisco un IEnumerable<string>
a te, sai che puoi tranquillamente supporre che tutto quello che viene restituito sarà un riferimento di stringa o null. Con IEnumerable
, abbiamo dovuto eseguire il cast efficace (spesso implicitamente in un'istruzione foreach
) ogni elemento restituito dalla sequenza, poiché la proprietà Current
di IEnumerator
è solo di tipo object
.Per quanto riguarda il motivo per cui abbiamo ancora necessario IEnumerable
- perché le vecchie interfacce non vanno mai via, in pratica. C'è troppo codice esistente che lo usa.
Sarebbe stato possibile per IEnumerable<T>
non estendere IEnumerable
, ma poi qualsiasi codice che vogliono fare uso di un IEnumerable<T>
non poteva mettere in un metodo accettare IEnumerable
- e c'erano un sacco di metodi come quello da .NET 1.1 e 1.0.
+1 La vita sarebbe stata molto più semplice se i generici l'avessero convertito in .NET 1.0 ... – Oded
@Jon: la domanda è: perché abbiamo anche bisogno di implementare 'IEnumerable' quando implementiamo già' IEnumerable ' , o vice versa? –
Nawaz
@Nawaz: Ho modificato la mia risposta. Quanto sei a tuo agio con l'idea del perché i farmaci generici sono una buona cosa? –