Domanda

Qual è il tipo di contenitore preferito quando si restituiscono più oggetti dello stesso tipo da una funzione?

È contro la buona pratica restituire un array semplice (come MyType []), o dovresti avvolgerlo in un contenitore generico (come ICollection < MyType >)?

Grazie!

È stato utile?

Soluzione

Eric Lippert ha un buon articolo su questo. Nel caso in cui non ti preoccupi di leggere l'intero articolo, la risposta è: restituisci l'interfaccia.

Altri suggerimenti

Restituisce un IEnumerable<T> utilizzando un yield return .

Vorrei restituire un IList<T> poiché ciò offre al consumatore della tua funzione la massima flessibilità. In questo modo se il consumatore della tua funzione aveva solo bisogno di enumerare la sequenza, può farlo, ma se vuole usare la sequenza come un elenco può farlo anche.

La mia regola generale è accettare il tipo meno restrittivo come parametro e restituire il tipo più ricco possibile. Questo è, ovviamente, un atto di bilanciamento in quanto non vuoi bloccarti in una particolare interfaccia o implementazione (ma cerca sempre di usare sempre un'interfaccia).

Questo è l'approccio meno presuntuoso che tu, lo sviluppatore dell'API, puoi adottare. Non spetta a te decidere in che modo un consumatore della tua funzione utilizzerà ciò che ti invia, ecco perché in questo caso restituiresti un IEnumerable<T> in modo da offrire loro la massima flessibilità. Inoltre, per lo stesso motivo, non presumeresti mai di sapere quale tipo di parametro ti verrà inviato da un consumatore. Se devi solo iterare una sequenza che ti è stata inviata come parametro, imposta il parametro un List<T> anziché un <=>.


EDIT (monossido): poiché non sembra che la domanda verrà chiusa, voglio solo aggiungere un link dall'altra domanda a riguardo: Perché gli array sono dannosi

Perché non List<T>?

Dal post di Eric Lippert menzionato da altri, ho pensato di evidenziarlo:

  

Se ho bisogno di una sequenza che & # 8217; userò   IEnumerable<T>, se ho bisogno di una mappatura   da numeri contigui a dati I & # 8217; ll   utilizzare un Dictionary<K,V>, se ho bisogno di una mappatura   su dati arbitrari I & # 8217; userò a   HashSet<T>, se ho bisogno di un set I & # 8217; ll   usa un <=>. Semplicemente non ho bisogno di & # 8217;   array per qualsiasi cosa, quindi quasi mai   usali. Non risolvono un problema   avere meglio degli altri strumenti al mio   disposizione.

Se la raccolta che viene restituita è di sola lettura, il che significa che non si desidera mai che gli elementi nella raccolta vengano modificati, quindi utilizzare IEnumerable<T>. Questa è la rappresentazione più elementare di una sequenza di sola lettura di elementi immutabili (almeno dal punto di vista dell'enumerazione stessa).

Se vuoi che sia una raccolta autonoma che può essere modificata, usa ICollection<T> o IList<T>.

Ad esempio, se si desidera restituire i risultati della ricerca di un determinato set di file, quindi restituire IEnumerable<FileInfo>.

Tuttavia, se si desidera esporre i file in una directory, tuttavia, si dovrebbe esporre IList/ICollection<FileInfo> poiché ha senso che si desideri modificare il contenuto della raccolta.

Un buon consiglio che ho sentito spesso citato è questo:

  

Sii liberale in ciò che accetti, preciso in ciò che fornisci.

In termini di progettazione dell'API, suggerirei di restituire un'interfaccia, non un tipo concreto.

Prendendo il tuo metodo di esempio, lo riscriverei come segue:

public IList<object> Foo() 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}

La chiave è che la tua scelta di implementazione interna - di usare un Elenco - non viene rivelata al chiamante, ma stai restituendo un'interfaccia appropriata.

Le linee guida di Microsoft sullo sviluppo del framework sconsigliano di restituire tipi specifici, favorendo le interfacce. (Mi dispiace, non sono riuscito a trovare un link per questo)

Allo stesso modo, i tuoi parametri dovrebbero essere il più generali possibile - invece di accettare un array, accetta un IEnumerable del tipo appropriato. Questo è compatibile con array, nonché elenchi e altri tipi utili.

Riprendendo il tuo metodo di esempio:

public IList<object> Foo(IEnumerable<object> bar) 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}
return ICollection<type>

Il vantaggio dei tipi di restituzione generici è che puoi cambiare l'implementazione sottostante senza cambiare il codice che la utilizza. Il vantaggio di restituire il tipo specifico è che puoi utilizzare metodi più specifici per tipo.

Restituisce sempre un tipo di interfaccia che presenta al chiamante la massima quantità di funzionalità. Quindi nel tuo caso ICollection<YourType> dovrebbe essere usato.

Qualcosa di interessante da notare è che gli sviluppatori BCL hanno effettivamente sbagliato in qualche posto del framework .NET - vedi questo post sul blog di Eric Lippert per quella storia.

Perché non IList<MyType>?

Supporta l'indicizzazione diretta che è il segno distintivo di un array senza rimuovere la possibilità di restituire un List<MyType> un giorno. Se si desidera sopprimere questa funzione, è probabile che si desideri restituire IEnumerable<MyType>.

Dipende da cosa pensi di fare con la raccolta che stai restituendo. Se stai solo iterando o se desideri che l'utente esegua l'iterazione, sono d'accordo con @Daniel, restituendo IEnumerable<T>. Se in realtà si desidera consentire operazioni basate su elenco, tuttavia, restituirei IList<T>.

Usa generici. È più facile interagire con altre classi di raccolte e il sistema dei tipi è più in grado di aiutarti con potenziali errori.

Il vecchio stile di restituire un array era una stampella prima dei generici.

Ciò che rende il tuo codice più leggibile, gestibile e più facile per TE. Avrei usato l'array semplice, il più semplice == meglio il più delle volte. Anche se devo davvero vedere il contesto per dare la risposta giusta.

Ci sono grandi vantaggi nel favorire IEnumerable rispetto a qualsiasi altra cosa, in quanto ciò ti offre la massima flessibilità di implementazione e ti consente di usare yield return o operatori Linq per un'implementazione pigra.

Se il chiamante vuole un List<T> invece può semplicemente chiamare ToList() su qualsiasi cosa tu abbia restituito e le prestazioni complessive saranno all'incirca le stesse di quelle che hai creato e restituito un nuovo <=> dal tuo metodo.

L'array è dannoso, ma anche ICollection<T> è dannoso.

ReadOnlyCollection<T> non può garantire che l'oggetto sarà immutabile.

La mia raccomandazione è di avvolgere l'oggetto di ritorno con <=>

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