2009-11-19 12 views
26

Esiste un modo per restituire facoltativamente un valore null con un iteratore "return yield" guidato?Ritorno rendimento con Null

Vorrei restituire un valore null in alcuni casi e non penso che questo sia specifico per IEnumerable di tipo stringa. Lo stesso vale per IEnumerable di tipo int ecc Grazie

static void Main(string[] args) 
{ 
    var Items = GetItems(); 

    if (Items != null) 
    { 
     foreach (var item in Items) 
     { 
      Console.WriteLine(item); 
     } 
    } 
    else 
    { 
     Console.WriteLine("<null>"); 
    } 
} 

static IEnumerable<string> GetItems() 
{ 
    if (false) 
    { 
     yield return "Andy"; 
     yield return "Jennifer"; 
    } 

    return null; // <- Compiler Error: 
    // Cannot return a value from an iterator. 
    // Use the yield return statement to return a value, 
    // or yield break to end the iteration. 
} 

risposta

34

Se avete bisogno di cose come che (o buttare cose come ArgumentException immediatamente), è necessario separare il vostro iteratore in due metodi:

public IEnumerable<string> GetItems() { 
    if (something) return null; 
    return GetItemsInternal(); 
} 

private IEnumerable<string> GetItemsInternal() { 
    // the actual iterator with "yield return" goes here. 
} 
+1

la risposta a quello che ho chiesto, ma probabilmente mquander postato un approccio più corretto. – andleer

26

Non stai utilizzando un enumerabile come è stato destinato (per iterare gli oggetti in una raccolta). Se si desidera mantenere il vostro codice simile a quello che è ora, si dovrebbe fare qualcosa di simile:

static void Main(string[] args) 
{ 
    var Items = GetItems(); 

    foreach (var item in Items) //this will not enter the loop because there are no items in the Items collection 
    { 
      Console.WriteLine(item); 
    } 

    //if you still need to know if there were items, check the Count() extension method 
    if(Items.Count() == 0) 
    { 
     Console.WriteLine("0 items returned"); 
    } 


} 

static IEnumerable<string> GetItems() 
{ 
    if (false) 
    { 
     yield return "Andy"; 
     yield return "Jennifer"; 
    } 

    yield break; 
} 
6

Non v'è alcun modo per restituire un valore NULL IEnumerable<T> da all'interno di un metodo iteratore. È possibile restituire valori nulli nel iteratore ma non un nulla IEnumerable<T>

cosa si potrebbe fare se è avere un metodo involucro che o restituisce un valore nullo o chiama al reale iteratore

static IEnumerable<string> GetItems() { 
    if (false) { 
     return GetItemsCore(); 
    } 
    return null; 
} 

static IEnumerable<string> GetItemsCore() { 
    yield return "Andy"; 
    yield return "Jennifer"; 
} 
12

Questo semplicemente non è incoraggiata. Quando parli di una sequenza, "null" dovrebbe generalmente avere la stessa semantica di "lista vuota".

Inoltre, è impossibile progettare la lingua in modo che funzioni nel modo in cui si desidera che funzioni qui senza sintassi aggiuntiva, dal momento che cosa si otterrebbe premendo "yield return [whatever]" e quindi "return null?"

+2

Sono d'accordo, è una questione di intenti. Semplicemente cadendo attraverso la funzione senza colpire un "yield return" genererà una sequenza vuota. La resposabilità per il controllo è che la sequenza vuota appartiene a qualcos'altro. –

+1

Non è stato rilevato che la caduta genera una sequenza vuota. Informazioni molto utili per me. Grazie. – ryanulit

2

Non c'è nulla che ti impedisce di fare un yield return null;, se è appropriato (ovviamente, il tipo enumerato deve essere annullabile).

+3

Sarei incazzato se ricevessi null da quello che pensavo fosse IEnumerable. Sì, potresti renderlo una stringa nullable nel caso, ma perché? – scottm

+0

Non ho detto che lo raccomando, ho appena detto che è possibile. E btw: una stringa è un tipo di dati nullable ... –

+0

Penso che il grosso problema con questo approccio sia che non c'è coerenza. Cosa succede se alcuni elementi sono nulli e altri hanno valore? Cosa indica? – andleer

3

Mentre yield break è stata riordinata la migliore risposta e davvero non importa dal momento che si può sempre fare Items.Count() per verificare se una maggiore zero o addirittura fare for each on your empty result ci potrebbero essere situazioni in cui non importa se il risultato è una lista vuota o nulla tutto e tu vuoi ancora utilizzare il potere della resa.

In tal caso ciò sarà di aiuto.

private IEnumerable<T> YieldItems<T>(IEnumerable<T> items, Action empty = null) 
    { 
     if (items == null) 
     { 
      if (empty != null) empty(); 
      yield break; 
     } 

     foreach (var item in items) 
     { 
      yield return item; 
     } 
    } 

Uso

 foreach (var item in YieldItems<string>(null,() => 
     { 
      Console.WriteLine("Empty"); 
     })) 
     { 
      Console.WriteLine(item); 
     } 
Problemi correlati