Randament Randament cu Null (Programare, C#)

andleer a intrebat.

Există vreo modalitate de a returna opțional un null cu un iterator condus de „return yield”?

Aș dori să returnez un null în unele cazuri și nu cred că acest lucru este specific pentru IEnumerable de tip string. Același lucru este valabil și pentru IEnumerable de tip int etc. Mulțumesc

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.
}

6 răspunsuri
mmx

Dacă aveți nevoie de lucruri de genul acesta (sau aruncați lucruri de genul ArgumentException imediat), trebuie să vă separați iteratorul în două metode:

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

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

Comentarii

  • răspunsul la ceea ce am cerut, dar mquander probabil a postat o abordare mai corectă. –  > Por andleer.
scottm

Nu folosiți un enumerabil așa cum a fost conceput (pentru a itera obiectele dintr-o colecție). Dacă doriți să vă păstrați codul similar cu cel de acum, ar trebui să faceți ceva de genul acesta:

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;
}

mqp

Acest lucru pur și simplu nu este încurajat. Când vorbiți despre o secvență, „null” ar trebui să aibă, în general, aceeași semantică ca și „lista goală”.

De asemenea, este imposibil să concepi limbajul pentru a funcționa în modul în care ai dori să funcționeze aici fără sintaxă suplimentară, deoarece ce s-ar întâmpla dacă ai nimeri un „yield return [whatever]” și apoi un „return null?”

Comentarii

  • Sunt de acord, este o chestiune de intenție. Simpla trecere prin funcție fără a lovi un „yield return” va genera o secvență goală. Responsabilitatea de a verifica dacă secvența goală aparține la altceva. –  > Por Binary Worrier.
  • Nu am fost conștient de faptul că trecerea prin genera o secvență goală. Informații foarte utile pentru mine. Mulțumesc. –  > Por ryanulit.
JaredPar

Nu există nicio modalitate de a returna un null IEnumerable<T> din cadrul unei metode iterator. Puteți returna valori nule în iterator, dar nu și un null. IEnumerable<T>

Ceea ce ați putea face totuși este să aveți o metodă wrapper care fie returnează null, fie apelează la iteratorul real

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

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

Jürgen Steinblock

În timp ce yield break este probabil cel mai bun răspuns și chiar nu contează, deoarece puteți face întotdeauna Items.Count() pentru a verifica dacă este mai mare decât zero sau chiar să faceți for each on your empty result ar putea exista situații în care contează dacă rezultatul este o listă goală sau nimic și totuși doriți să utilizați puterea randamentului.

În acest caz, acest lucru vă va ajuta.

    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;
        }
    }

Utilizare

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

Thomas Weller

Nu există nimic care să vă împiedice să faceți un yield return null;, dacă este adecvat (desigur, tipul enumerat trebuie să fie nul).

Comentarii

  • Aș fi supărat dacă aș primi null de la ceea ce am crezut că este IEnumerable. Da, ai putea să faci un șir de caractere nullable în cazul respectiv, dar de ce? –  > Por scottm.
  • Nu am spus că recomand acest lucru, am spus doar că este posibil. Și btw: Un șir de caractere ESTE un tip de date care poate fi anulat… –  > Por Thomas Weller.
  • Cred că marea problemă cu această abordare este că nu există consistență. Ce se întâmplă dacă unele elemente sunt nule și altele au valoare? Ce indică acest lucru? –  > Por andleer.

Tags: