2009-08-13 14 views
12

Ho una funzione che restituisce un numero variabile di elementi, dovrei restituire un array o un elenco? La dimensione della "collezione" non cambia una volta restituita, cioè per tutti gli scopi la collezione è immutabile. Penserei solo a restituire un array, ma alcune persone hanno detto di non restituire array di dimensioni variabili da una funzione poichè è una "forma scadente". Non sai perché?È una cattiva forma restituire gli array in C#? Devo restituire la lista <T>?

È importante che questo sia compatibile con .NET 2.0?

+0

Perché gli array in C# sono malvagi? So che in C/C++ sono malvagie, perché un array e un puntatore sono uguali – user142350

+2

hai visto questo? http://stackoverflow.com/questions/434761/array-versus-listt-when-to-use-which – elan

+2

Odio il termine "X programming construct is evil", usato troppo spesso. Gli array non sono preferiti perché possono essere soggetti a errori con cui lavorare e forniscono meno astrazione tra te e l'implementazione. Onestamente, in C# scompaiono molti dei problemi inerenti agli array C++, ma un IList (o qualche altra raccolta) è un'interfaccia più gradevole e di livello più alto. –

risposta

20

È una cattiva forma restituire gli array se non necessario e soprattutto restituire List<T>.

In genere, è necessario restituire IEnumerable<T> o IList<T>.

Se l'utente deve solo passare attraverso ogni elemento, IEnumerable<T> fornirà questa funzionalità. Consente inoltre di implementare potenzialmente la routine (ora o più tardi) utilizzando l'esecuzione posticipata.

Se l'utente deve accedere agli elementi per indice, restituire IList<T>. Ciò fornisce tutti i vantaggi degli array, ma offre una maggiore flessibilità nell'implementazione. Puoi implementarlo come una matrice, un elenco o un'altra raccolta che implementa IList<T> e non devi convertire/copiare in un array.

+0

Sono andato con la lista perché la funzione ConvertAll era davvero utile in questo caso. – DevDevDev

+0

Posso ottenere la lunghezza di un tipo IEnumerable? – DevDevDev

+0

L'elenco è contro le linee guida di progettazione. LINQ fornisce i mezzi per ottenere conteggi e casting, per IEnumerable e IList . –

6

Un parere Vedo spesso un suggerimento per restituire sia IList<T> o ReadOnlyCollection<T>. Va bene restituirli se ne hai uno disponibile: entrambi possono essere assegnati direttamente a un IEnumerable<T> (funzionano direttamente con qualsiasi metodo LINQ). Una cosa da notare è ReadOnlyCollection<T> è un tipo molto leggero che può avvolgere qualsiasi IList<T>.

+1

+1 per 'ReadOnlyCollection' –

0

Se la dimensione della raccolta non deve essere modificata dopo la restituzione, la scelta è IEnumerable<T>, poiché il chiamante potrebbe quindi utilizzare immediatamente i metodi di estensione LINQ con l'elenco.

0

E 'facile per ottenere un array da un IList se un array è quello che ti serve, ma il contrario non è vero. Quindi è preferibile restituire un IList.

1

Come avete visto indubbiamente dalle risposte in questo thread, le opinioni su questo argomento sono molto ampie.

In generale, i miei pensieri sono i seguenti:

Se torno una lista i cui taglia è costante e non voglio che il chiamante sia in grado di modificare i miei dati (che è il 99% del tempo), Restituirò un ReadOnlyCollection<T>. Ciò mi dà immutabilità sul lato client senza dover raddoppiare (o triplicare o qualsiasi altra cosa) l'impronta di memoria dei miei dati nella creazione di un nuovo elenco o di un array.

Ho esitato a dire che "si dovrebbe sempre restituire IEnumerable o IEnumerable<T>".Sebbene ciò sia certamente appropriato in alcuni casi (e questi casi non sono pochi), la natura leggera dell'interfaccia IEnumerable limita notevolmente le funzionalità (nessun recupero basato su indice è il più grande) e in molti casi la fonte di dati sottostante è sta per essere un array in ogni caso, anche se è un List<T>.

Un ulteriore pericolo di restituire IEnumerable deriva dalla pratica pigra di restituire semplicemente l'elenco interno nel contesto di tale interfaccia. Ciò ti espone al metodo di chiamata che abusa di questa scorciatoia riportandolo al tipo di raccolta più affidabile. Un buon programmatore difensivo non lo farà.

Il minor ingombro di memoria deriva dall'utilizzo di uno ReadOnlyCollection generato da un List. Un ReadOnlyCollectionfa ancora esporre a pericolo attraverso l'abuso basato sulla riflessione e catturare un riferimento alla lista mutabile, ma questo è un po 'un caso marginale.

+1

" ... espone al metodo di chiamata abusando di questo collegamento riconducendolo al tipo di raccolta più affidabile.Un buon programmatore difensivo non lo farà. " Fesserie.La responsabilità della biblioteca è quella di creare un'interfaccia chiara per il cliente. La responsabilità della biblioteca * non è * di anticipare il client basando il suo codice sugli interni della biblioteca. Usando IEnumerable , stai dicendo al cliente che tutto quello che garantisci è che riceverà una lista di articoli che può passare. Se ritorna al tuo tipo interno, è * la sua * colpa, non la tua, se il suo codice si rompe con una versione futura. –

+1

@Kyralessa: la programmazione difensiva sta scrivendo un codice progettato in modo tale da eliminare (o, più realisticamente, limitare) il potenziale di abuso da parte di un chiamante. Il casting è un aspetto comune e necessario dello sviluppo, e minimizzare questo pericolo è sconsiderato. La situazione che descrivo è una parte molto ampia del perché ReadOnlyCollection esiste, in quanto è un'istanza NEW che punta allo stesso oggetto, piuttosto che visualizzare lo stesso oggetto attraverso un'interfaccia diversa. –

+0

Bene, puoi sempre ottenere il meglio da entrambi i mondi: restituire un ReadOnlyCollection , ma il tuo metodo è effettivamente digitato come un oggetto IEnumerable . Quindi stai solo garantendo l'enumerabilità, ma se la trasmettono a un IList o qualcosa del genere, non gli permetteranno comunque di modificarlo a causa del modo in cui IList è implementato in ReadOnlyCollection . –

0

ritorno IEnumerable a meno che non è necessario:

  1. accesso Conte - per poi tornare IReadOnlyCollection.
  2. modifica elementi e Conteggio è inferiore a ArrayList.Capacity - quindi restituisce matrice.
  3. aggiungi nuovi elementi - quindi torna all'elenco.
  4. alcune microottimazioni: fare benchmark. Per esempio. foreach su array è più veloce quindi oltre l'elenco

BenchmarkDotNet = v0.10.8, OS = Windows 10 Redstone 1 (10.0.14393) processore Intel Core i5-2500K = CPU 3.30GHz (Sandy Bridge), ProcessorCount = 4 Frequenza = 3.233.538 Hz, risoluzione = 309.2588 ns, Timer = TSC [host]: Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1648.0 Clr: Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1648.0 nucleo: NET nucleo 4.6.25211.01, 64bit RyuJIT

Method | Job | Runtime |  Mean |  Error | StdDev |  Min |  Max |  Median | Rank | Allocated | 
---------- |----- |-------- |-----------:|-----------:|----------:|-----------:|-----------:|-----------:|-----:|----------:| 
    TestList | Clr |  Clr | 5,153.3 ns | 34.002 ns | 31.806 ns | 5,119.2 ns | 5,213.4 ns | 5,135.9 ns | 3 |  0 B | 
TestArray | Clr |  Clr | 730.1 ns | 6.962 ns | 6.512 ns | 722.4 ns | 743.9 ns | 729.5 ns | 2 |  0 B | 
    TestList | Core | Core | 5,188.4 ns | 102.816 ns | 96.174 ns | 5,070.3 ns | 5,342.6 ns | 5,185.6 ns | 3 |  0 B | 
TestArray | Core | Core | 709.0 ns | 6.126 ns | 5.730 ns | 700.8 ns | 718.6 ns | 708.1 ns | 1 |  0 B | 

Codice:

[RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn] 
[ClrJob, CoreJob] 
[HtmlExporter, MarkdownExporter] 
[MemoryDiagnoser] 
public class BenchmarkForEach 
{ 
    List<string> testData = new List<string>(); 
    string[] testArray; 
    public BenchmarkForEach() 
    { 
     for(int i=0;i<1000;i++) 
     { 
      testData.Add(i.ToString()); 
     } 
     testArray = testData.ToArray(); 
    } 
    [Benchmark] 
    public int TestList() 
    { 
     var x = 0; 
     foreach(var i in testData) 
     { 
      x += i.Length; 
     } 
     return x; 
    } 
    [Benchmark] 
    public int TestArray() 
    { 
     var x = 0; 
     foreach (var i in testArray) 
     { 
      x += i.Length; 
     } 
     return x; 
    } 

} 
Problemi correlati