2011-08-30 9 views
20

C'è già uno question on SO about "possible multiple enumerations", ma questa domanda è più specifica.Anche i controlli "IsNullOrEmpty" danno "possibili enumerazioni multiple di avvisi IEnumerable"

perche il seguente metodo, che prende un IEnumerable<string> come input ed esegue un dato metodo contro ciascuno dei suoi elementi:

public static bool SomeMethod(IEnumerable<string> enumerable) 
{ 
    if (enumerable.IsNullOrEmpty()) 
    { 
     // throw exception. 
    } 
    else 
    { 
     return (enumerable.All(SomeBooleanMethod)); 
    } 
} 

Nel codice precedente, IsNullOrEmpty è solo un metodo di estensione che corre

return (!ReferenceEquals(enumerable, null) || enumerable.Any()); 

Il problema è che ReSharper mi avvisa di "Possibili enumerazioni multiple di IEnumerable" e davvero non so se questo può effettivamente essere un problema o meno.

Capisco il significato dell'avviso, ma cosa potresti fare davvero in questa situazione se davvero hai bisogno di controllare e lanciare un'eccezione in caso di nullità o vuoto?

+0

Perché si desidera che questo metodo passi se viene passata una sequenza vuota? La semantica di "Fai qualcosa ad ogni membro di questa sequenza (vuota)" è perfettamente ovvia, vero? Inoltre, c'è qualche ragione particolare per cui usi 'ReferenceEquals()' piuttosto che solo '== null'? – AakashM

+0

In effetti non lo è, ma ora immagina che fosse un costruttore. Se non riesco a costruire un oggetto da una sequenza vuota, non dovrei lanciare un'eccezione? – User

+1

Certo, se non c'è davvero nulla che tu possa fare; ma * in generale * direi che le sequenze vuote dovrebbero essere considerate valide quanto le sequenze non vuote. 'Lista <>' è perfettamente felice di costruire da una sequenza vuota, per esempio. Certo che sto parlando solo in generalità; conosci i * dettagli * della tua situazione. – AakashM

risposta

30

Significa che si sta effettuando (parzialmente) iterando su IEnumerable più di una volta: prima nella propria chiamata a Any() (che deve almeno inizializzare un'iterazione per verificare se l'enumerable restituisce qualsiasi elemento) e una seconda volta in All (che itera dall'inizio).

La ragione per cui ReSharper ti avverte è che elencare su un numero enumerabile può causare effetti collaterali e due volte l'iterazione involontaria può attivare due volte gli effetti collaterali, il che può essere o meno desiderabile.

+0

potresti per favore spiegare gli effetti collaterali o qualsiasi esempio sarebbe delizioso. –

+12

L'enumerabile potrebbe, ad esempio, leggere byte da un flusso di rete (che costituirebbe un effetto collaterale). Se si enumera una volta, tutto va bene e lo stream viene letto dall'inizio alla fine in un colpo solo. Se, tuttavia, si interrompe la prima iterazione e poi si ripete nuovamente, anche se il flusso di rete sottostante non può cercare all'indietro, molto probabilmente si otterrà un comportamento indesiderato. – tdammers

+0

grazie per l'esempio –

8

Come identifica @tdammers, le "enumerazioni multiple" a cui si fa riferimento sono le due enumerazioni richieste da Any e All. Dal momento che si desidera rifiutare una sequenza vuota, il meglio che riesco a trovare è:

public static bool SomeMethod(IEnumerable<string> enumerable) 
{ 
    if (enumerable == null) 
     throw new ArgumentNullException(); 

    // Manually perform an All, keeping track of if there are any elements 
    bool anyElements = false; 

    bool result = true; 

    foreach (string item in enumerable) 
    { 
     anyElements = true; 
     result = result && SomeBooleanMethod(item); 

     // Can short-circuit here 
     if (!result) 
      break; 
    } 

    if (!anyElements) 
     throw new ArgumentException(); // Empty sequence is invalid argument 

    return result; 
} 
+1

Upvoting for effort. –

Problemi correlati