2009-10-20 14 views
9

È stato chiesto un paio di volte su SO come è possibile implementare un enumeratore bidirezionale (here, here). La mia domanda non è come (che è banale nella maggior parte dei casi), ma perché non esiste questo tipo nella piattaforma .NET.Perché .NET non ha un enumeratore bidirezionale?

public interface IBidirectionalEnumerator<T> : IEnumerator<T> 
{ 
    bool MovePrev(); 
} 

Ovviamente, ci sono molti tipi di raccolta che non possono implementano questo, come MoveNext() è distruttivo o cambia lo stato della raccolta sottostante. Al contrario, molti tipi possono implementare questo banalmente (List, IList, LinkedList, array).

Perché questo tipo non esiste?

+4

C'è qualcosa di molto sbagliato nella progettazione della raccolta se l'operazione di enumerazione cambia il suo stato. – Joren

+0

concordato. Ma ci sono davvero alcune collezioni che cambiano mentre si enumerano, come una pila o una coda. –

+2

A meno che non si utilizzi IEnumerable avvolto su un tipo di streaming o su una risorsa di sistema come StreamReader o elenco di file. –

risposta

3
  • IEnumerator supporta l'istruzione foreach C# nonché i costrutti di looping di altre lingue.
  • Non esiste alcuna istruzione o linguaggio di programmazione comune abilitato da IBidirectionalEnumerator.
+1

Questo non è completamente vero. C# richiede solo il metodo 'MoveNext' e la proprietà' Current' per funzionare. Non si basa affatto sull'interfaccia. –

+3

In realtà 'IEnumerator ' non è necessario per 'foreach'. Finché la tua classe ha un metodo 'GetEnumerator()' che non accetta parametri e restituisce un oggetto che ha un oggetto Current {get; } 'proprietà e un metodo' void MoveNext() ', quindi' foreach' funzionerà abbastanza felicemente con esso. –

+0

Greg: Davvero ?! Quindi l'IEnumerator è effettivamente digitato a forma di anatra? Questa è una rivelazione. –

2

Perché o nessuno pensava, o nessuno pensava che sarebbe particolarmente utile, o perché non c'era abbastanza budget o ...

In realtà non è necessario, è vero? Puoi facilmente implementarlo da solo. Forse il team BCL ha pensato che non valesse la pena di implementare, testare, documentare, ecc. Non sottovalutare mai il costo di una funzionalità, potrebbe sembrare "facile", ma ha dei costi.

Particolare perché una singola interfaccia che nessuno strumento sembra strano, non è vero? Ci si aspetterebbe che List, Array ecc. Implementino l'interfaccia, che alla fine è piuttosto impegnativa.

+0

Heh, come ICloneable. = P –

+0

Come direbbe Raymond Chen, tutte le caratteristiche iniziano con -100 punti. –

1

Inoltre, quale sarebbe la motivazione per questo? Supporto linguistico per iterazione "arretrata"?

Il pattern iteratore non dà molto peso al concetto di "directionality" di un insieme di elementi. È un modello semplice per fornire un'interfaccia semplice per iterare su un set.

4

Quando si progetta un framework, è necessario prendere decisioni su come fare cose a diversi livelli di astrazione. Il compromesso è che se scegli di esporre le cose ad un livello di astrazione elevato, otterrai una generalizzazione a costo di perdere il controllo a grana fine sulle cose. Se scegli di esporre cose a livelli di astrazione più bassi, il tuo concetto non può essere generalizzato, ma puoi controllare i dettagli a un livello inferiore.

È una decisione di progettazione. L'implementazione di entrambi sarà costosa e renderà la struttura più gonfia e sarà necessario supportare sia quando si aggiungono funzionalità. Avrai bisogno di preservare la compatibilità con le versioni precedenti in futuro. Non è una cosa saggia aggiungere tutto ciò che si può pensare al BCL senza accertarsi che abbia un vantaggio significativo.

2

Ovviamente, ci sono molti tipi di raccolta che non possono implementarlo, dato che MoveNext() è distruttivo o cambia lo stato della raccolta sottostante.

MoveNext() non è distruttivo.Infatti, se lo stato della raccolta sottostante viene modificato tra il momento in cui è stato creato lo IEnumerator e viene richiamata l'ora MoveNext(), la chiamata a MoveNext() avrà esito negativo.

Lo scopo di IEnumerator è quello di iterare su tutti gli elementi di una raccolta una volta, nell'ordine nativo della raccolta se la raccolta ha un ordine nativo. IEnumerator non è inteso come un dispositivo di raccolta-navigazione, come si potrebbe trovare in C++.

1

Una domanda più grande è perché .Net non implementa IReadableByIndex, che a sua volta sarebbe ereditato da IList. Un tal tipo non avrebbe aggiunto nulla al lavoro richiesto per produrre implementazioni IList read-write e avrebbe ridotto il lavoro richiesto per produrre implementazioni di sola lettura (che implementerebbero IReadableByIndex, piuttosto che IList).

Non è troppo utile riflettere su tali "perché", tuttavia. .Net è quello che è. L'unico modo per porre rimedio alla situazione di .Net 5.0 sarebbe quello di consentire un mezzo per dichiarare che un'interfaccia che implementa una proprietà read-write può essere considerata come implicita implementazione di una versione di sola lettura (in modo da permettere a IList di ereditare un covariante IReadableByIndex senza dover aggiungere un metodo Get esplicito).