Come posso restituire un IEnumerable vuoto?


329

Dato il seguente codice e i suggerimenti forniti in questa domanda , ho deciso di modificare questo metodo originale e chiedere se ci sono valori in IEnumarable restituirlo, se non restituire un IEnumerable senza valori.

Ecco il metodo:

public IEnumerable<Friend> FindFriends()
        {
            //Many thanks to Rex-M for his help with this one.
            //https://stackoverflow.com/users/67/rex-m

            return doc.Descendants("user").Select(user => new Friend
            {
                ID = user.Element("id").Value,
                Name = user.Element("name").Value,
                URL = user.Element("url").Value,
                Photo = user.Element("photo").Value
            });
        }

Poiché tutto è all'interno della dichiarazione di ritorno, non so come potrei farlo. Qualcosa del genere funzionerebbe?

public IEnumerable<Friend> FindFriends()
        {
            //Many thanks to Rex-M for his help with this one.
            //https://stackoverflow.com/users/67/rex-m
            if (userExists)
            {
                return doc.Descendants("user").Select(user => new Friend
                {
                    ID = user.Element("id").Value,
                    Name = user.Element("name").Value,
                    URL = user.Element("url").Value,
                    Photo = user.Element("photo").Value
                });
            }
            else
            { 
                return new IEnumerable<Friend>();
            }
        }

Il metodo sopra non funziona, e infatti non dovrebbe; Sento solo che illustra le mie intenzioni. Sento che dovrei specificare che il codice non funziona perché non è possibile creare un'istanza di una classe astratta.

Ecco il codice chiamante, non voglio che riceva un IEnumerable null in qualsiasi momento:

private void SetUserFriends(IEnumerable<Friend> list)
        {
            int x = 40;
            int y = 3;


            foreach (Friend friend in list)
            {
                FriendControl control = new FriendControl();
                control.ID = friend.ID;
                control.URL = friend.URL;
                control.SetID(friend.ID);
                control.SetName(friend.Name);
                control.SetImage(friend.Photo);

                control.Location = new Point(x, y);
                panel2.Controls.Add(control);

                y = y + control.Height + 4;
            } 

        }

Grazie per il tuo tempo.


2
Guardando il codice qui dovresti usare il rendimento e l'interruzione del rendimento.
Chris Marisic,

Risposte:


575

Puoi usare list ?? Enumerable.Empty<Friend>()o avere un FindFriendsresoEnumerable.Empty<Friend>()


7
Cambierebbe le cose se fosse tornato, diciamo, new List<Friend>()dato che verrebbe lanciato IEnumerable<Friend>quando restituito da quel metodo?
Sarah Vessels,

73
new List<Friend>()è un'operazione più costosa perché creerebbe un'istanza di un elenco (e allocare memoria per esso nel processo)
Igor Pashchuk,


106

Per quanto mi riguarda, il modo più elegante è yield break


8
Ma è se usi il rendimento e così via, no?
Svish,

15
+1 come codice corretto dovrebbe usare la resa per il modo in cui lavora con IEnumerable
Chris Marisic,

6
Perdonate la mia ignoranza sull'argomento, ma potreste per favore illustrare come utilizzare l'interruzione del rendimento in questo contesto? Ho visto esempi solo per i loop, ma questo non mi dà un'immagine chiara.
Sergio Tapia,

Aggiornato la risposta con un esempio. Sono davvero il modo più elegante di farlo, sarei d'accordo. :)
Johny Skovdal,

4
La modifica è stata rifiutata in peer review, quindi ecco l'esempio di cui parlavo di @Pyritie: la formattazione è incasinata, quindi l'ho aggiunta anche a pastebin.com/X9Z49Vq1 :public IEnumerable<Friend> FindFriends() { if(!userExists) yield break; foreach(var descendant in doc.Descendants("user").Select(user => new Friend { ID = user.Element("id").Value, Name = user.Element("name").Value, URL = user.Element("url").Value, Photo = user.Element("photo").Value })) { yield return descendant; } }
Johny Skovdal

8

Ovviamente è solo una questione di preferenze personali, ma scriverei questa funzione usando il rendimento:

public IEnumerable<Friend> FindFriends()
{
    //Many thanks to Rex-M for his help with this one.
    //http://stackoverflow.com/users/67/rex-m
    if (userExists)
    {
        foreach(var user in doc.Descendants("user"))
        {
            yield return new Friend
                {
                    ID = user.Element("id").Value,
                    Name = user.Element("name").Value,
                    URL = user.Element("url").Value,
                    Photo = user.Element("photo").Value
                }
        }
    }
}

1

Penso che il modo più semplice sarebbe

 return new Friend[0];

I requisiti del ritorno sono semplicemente che il metodo restituisce un oggetto che implementa IEnumerable<Friend>. Il fatto che in circostanze diverse si restituiscano due diversi tipi di oggetti è irrilevante, purché entrambi implementino IEnumerable.


5
Enumerable.Empty <T> restituisce effettivamente una matrice vuota di T (T [0]), con il vantaggio che la stessa matrice vuota viene riutilizzata. Si noti che questo approccio non è ideale per array non vuoti, poiché gli elementi possono essere modificati (tuttavia un array non può essere ridimensionato, il ridimensionamento implica la creazione di una nuova istanza).
Francis Gagné,

0
public IEnumerable<Friend> FindFriends()
{
    return userExists ? doc.Descendants("user").Select(user => new Friend
        {
            ID = user.Element("id").Value,
            Name = user.Element("name").Value,
            URL = user.Element("url").Value,
            Photo = user.Element("photo").Value
        }): new List<Friend>();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.