Domanda

C'è un problema con l'utilizzo IEnumerable<T> come un tipo di ritorno? FxCop lamenta ritorno List<T> (si consiglia di tornare Collection<T> invece).

Bene, sono sempre stato guidato da una regola di "accettare il minimo che puoi, ma tornare al massimo".

Da questo punto di vista, di ritorno IEnumerable<T> è una brutta cosa, ma cosa devo fare quando voglio usare "recupero pigro"? Inoltre, la parola chiave yield è una goodie.

È stato utile?

Soluzione

Questa è davvero una domanda in due parti.

1) C'è qualcosa di sbagliato intrinsecamente con la restituzione di un IEnumerable

No niente affatto. In realtà, se si sta utilizzando C # iteratori questo è il comportamento previsto. Convertendolo in un List o un'altra classe di raccolta preventivamente non è una buona idea. In questo modo è fare un presupposto sul modello di utilizzo per il chiamante. Trovo che non è una buona idea di assumere nulla circa il chiamante. Possono avere buone ragioni perché vogliono un IEnumerable . Forse vogliono convertirlo in una gerarchia di raccolta completamente diverso (nel qual caso è sprecato una conversione List).

2) Ci sono circostanze in cui può essere preferibile per tornare qualcosa di diverso da IEnumerable ?

Sì. Anche se non è una grande idea di assumere molto circa i chiamanti, è perfettamente bene di prendere decisioni in base al proprio comportamento. Immaginate uno scenario in cui si ha un oggetto multi-threaded che è stata la fila richieste in un oggetto che è stato costantemente aggiornato. In questo caso la restituzione di un oggetto IEnumerable grezzo è irresponsabile. Appena la raccolta viene modificato il enumerable viene invalidata e causerà un execption a verificarsi. Invece si potrebbe prendere una fotografia istantanea della struttura e restituire tale valore. Dire in una forma List . In questo caso sarebbe solo restituire l'oggetto come diretto con la struttura (o interfaccia).

Questo è certamente il caso più raro però.

Altri suggerimenti

No, IEnumerable<T> è un bene cosa di tornare qui, dal momento che tutto si sta promettente è "una sequenza di valori (digitati)". Ideale per LINQ, ecc, e perfettamente utilizzabile.

Il chiamante può facilmente mettere questi dati in un elenco (o altro) -. In particolare con LINQ (ToList, ToArray, etc)

Questo approccio consente di spool pigramente indietro valori, piuttosto che dover tamponare tutti i dati. Sicuramente un goodie. Ho scritto-up altro utile trucco IEnumerable<T> l'altro giorno , anche.

Informazioni sul principio:. "Accettare il minimo che puoi, ma tornare al massimo"

La chiave per gestire la complessità di un programma di grandi dimensioni è una tecnica chiamata information hiding . Se il metodo funziona con la costruzione di un List<T>, non è spesso necessario per rivelare questo fatto restituendo quel tipo. Se lo fai, allora i chiamanti possono modificare l'elenco tornano. Ciò elimina la vostra capacità di fare il caching, o l'iterazione pigro con yield return.

Quindi, un principio migliore è per una funzione da seguire è:. "Rivelano il meno possibile su come si lavora"

IEnumerable è per me va bene, ma ha alcuni svantaggi. Il cliente deve elencare per ottenere i risultati. Essa non ha modo di verificare la presenza di Conte, ecc List è un male perché si espone troppo controllo; il cliente può aggiungere / rimuovere ecc da esso e che può essere una cosa negativa. Collezione sembra il miglior compromomise, almeno nella visione di FxCop. Ho allways uso quello che sembra appropriata nel mio contesto (ad es. Se voglio restituire un sola lettura collezione espongo collezione come tipo di ritorno e ritorno List.AsReadOnly () o IEnumerable per la valutazione pigra attraverso la resa, ecc). Prendere su un caso per caso

"accettare il minimo che puoi, ma tornare al massimo" è ciò che io sostengo. Quando un metodo restituisce un oggetto, quello che abbiamo giustificazioni di non restituire il tipo effettivo e limitare le funzionalità dell'oggetto restituendo un tipo di base. Ciò solleva però una domanda come facciamo a sapere ciò che il "massimo" (tipo effettivo) sarà quando progettiamo un'interfaccia. La risposta è molto semplice. Solo in casi estremi in cui il progettista dell'interfaccia sta progettando un'interfaccia aperta, che sarà attuata al di fuori dell'applicazione / component, non saprebbero che cosa il tipo di ritorno effettiva può essere. Un progettista intelligente dovrebbe sempre prendere in considerazione ciò che il metodo dovrebbe fare e ciò che un tipo di ritorno ottimale / generico dovrebbe essere.

es. Se io sono la progettazione di un'interfaccia per recuperare un vettore di oggetti, e so che il conteggio degli oggetti restituiti stanno per essere variabile, sarò sempre assumo uno sviluppatore intelligente utilizzerà sempre una lista. Se qualcuno ha intenzione di restituire un array, mi piacerebbe in discussione le sue capacità, a meno che lui / lei è solo tornando i dati da un altro strato che lui / lei non possiede. E questo è probabilmente il motivo per FxCop sostiene per ICollection (base comune per la lista e Array).

È possibile che questo detto, ci sono un paio di altre cose da considerare

  • se i dati restituiti dovrebbero essere mutabile o immutabile

  • se i dati restituiti essere condivisi tra più chiamanti

Per quanto riguarda i LINQ valutazione lazy Sono sicuro al 95% + C # utenti non capiscono le intestacies. E 'così non oo-ish. OO promuove cambiamenti di stato concrete su chiamate di metodi. LINQ valutazione pigra promuove i cambiamenti di stato di esecuzione sul modello di valutazione di espressione (non qualcosa utenti non avanzati seguono sempre).

Tornando IEnumerable è OK se siete veramente solo la restituzione di un conteggio, e sarà consumata dal chiamante in quanto tale.

Ma, come altri sottolineano, ha l'inconveniente che il chiamante può essere necessario per enumerare se ha bisogno di qualsiasi altra informazioni (ad esempio, Count). Il metodo di estensione NET 3.5 IEnumerable Count enumererà dietro le quinte se il valore restituito non implementa ICollection , che può essere indesiderabile.

torno spesso IList o ICollection , quando il risultato è una collezione - internamente il metodo può utilizzare un List e sia restituirlo così com'è, o tornare List .AsReadOnly se voler proteggere contro le modifiche (ad esempio, se si sta caching l'elenco internamente). Per quanto ne sappia FxCop è molto felice con uno di questi.

Un aspetto importante è che quando si torna un List<T> sei effettiva restituzione di un di riferimento . Questo rende possibile per un chiamante per manipolare la vostra lista. Questo è un esempio comune problema-per, uno strato di business che restituisce un List<T> ad uno strato di interfaccia grafica.

Solo perché dici che stai tornando IEnumerable non significa che non si può restituire un elenco. L'idea è quella di ridurre l'accoppiamento non necessari. Tutto ciò che il chiamante dovrebbe preoccuparsi sta ottenendo un elenco di cose, piuttosto che il tipo esatto di raccolta utilizzato per contenere tale elenco. Se avete qualcosa che è sostenuta da una matrice, quindi ottenere qualcosa di simile a Conte sta per essere veloce in ogni caso.

Credo che la vostra propria guida è grande - se siete in grado di essere più specifico su quello che stai tornando, senza un calo di prestazioni (non c'è bisogno di costruire ad esempio una lista fuori del vostro risultato), farlo. Ma se la funzione legittimamente non sa che tipo che sta andando a trovare, come se in alcune situazioni lavorerete con una lista e in alcuni con una matrice, ecc, per poi tornare IEnumerable è il "migliore" che si può fare . Pensate a come "il più grande comune multiplo" di tutto ciò che si potrebbe desiderare di tornare.

Non posso accettare la risposta scelta. Ci sono modi di affrontare lo scenario descritto, ma utilizzando un elenco o qualsiasi altra cosa la vostra utilizzando non è uno di loro. Nel momento in cui l'IEnumerable viene restituito bisogna supporre che il chiamante potrebbe fare un foreach. In questo caso non importa se il tipo di calcestruzzo è List o spaghetti. Infatti solo indicizzazione è un problema soprattutto se vengono rimossi oggetti.

Qualsiasi valore restituito è una fotografia istantanea. Essa può essere il contenuto corrente del IEnumerable nel qual caso se è memorizzato nella cache che dovrebbe essere un clone del copia cache; se si suppone di essere più dinamici (come i resuts di una query SQL) quindi utilizzare dei rendimenti; tuttavia permettendo il contenitore di mutare a suo piacimento e la fornitura di metodi come Conte e indicizzatore è una ricetta per il disastro in un mondo multithread. Non ho ancora preso l'abilità del chiamante per chiamare aggiungere o eliminare su un contenitore il codice dovrebbe essere in controllo di.

tornare anche un tipo di cemento blocca si in un'implementazione. Oggi internamente si può utilizzare un elenco. Domani forse si diventa multithread e si desidera utilizzare un filo contenitore sicuro o un array o una coda o la raccolta dei valori di un dizionario o l'uscita di una query LINQ. Se vi blocca in un tipo di ritorno concreto, allora bisogna o cambiare un mucchio di codice o di fare un conversioni prima di tornare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top