Comment puis-je retourner un IEnumerable vide?


329

Étant donné le code suivant et les suggestions données dans cette question , j'ai décidé de modifier cette méthode d'origine et de demander s'il y a des valeurs dans le IEnumarable le renvoyer, sinon retourner un IEnumerable sans valeurs.

Voici la méthode:

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

Puisque tout est à l'intérieur de la déclaration de retour, je ne sais pas comment je pourrais faire cela. Quelque chose comme ce travail?

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

La méthode ci-dessus ne fonctionne pas, et en fait, elle n'est pas censée le faire; J'ai l'impression que cela illustre mes intentions. Je pense que je devrais spécifier que le code ne fonctionne pas parce que vous ne pouvez pas créer une instance d'une classe abstraite.

Voici le code appelant, je ne veux pas qu'il reçoive un IEnumerable nul à tout moment:

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

        }

Merci pour votre temps.


2
En regardant le code ici, vous devriez utiliser le rendement et la rupture de rendement.
Chris Marisic

Réponses:


575

Vous pouvez utiliser list ?? Enumerable.Empty<Friend>()ou avoir un FindFriendsretourEnumerable.Empty<Friend>()


7
Cela changerait-il les choses s'il revenait, disons, new List<Friend>()car il sera converti en IEnumerable<Friend>retour de cette méthode?
Sarah Vessels

73
new List<Friend>()est une opération plus coûteuse car elle créerait une instance d'une liste (et lui allouerait de la mémoire dans le processus)
Igor Pashchuk


106

Quant à moi, la façon la plus élégante est yield break


8
Mais c'est si vous utilisez le rendement et ainsi de suite, n'est-ce pas?
Svish

15
+1 car son code devrait utiliser correctement yield pour la façon dont il travaille avec IEnumerable
Chris Marisic

6
Excusez mon ignorance sur le sujet, mais pourriez-vous s'il vous plaît illustrer comment utiliser la rupture de rendement dans ce contexte? J'ai vu des exemples uniquement dans les boucles for, mais cela ne donne pas une image claire pour moi.
Sergio Tapia

Mise à jour de la réponse avec un exemple. C'est vraiment la façon la plus élégante de le faire, je suis d'accord. :)
Johny Skovdal

4
La modification a été rejetée lors de l'examen par les pairs, voici donc l'exemple dont je parlais @Pyritie - le formatage est cependant foiré, alors je l'ai également ajouté à 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

Ce n'est bien sûr qu'une question de préférence personnelle, mais j'écrirais cette fonction en utilisant le rendement de rendement:

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

Je pense que la façon la plus simple serait

 return new Friend[0];

Les exigences du retour sont simplement que la méthode retourne un objet qui implémente IEnumerable<Friend>. Le fait que, dans des circonstances différentes, vous renvoyiez deux types d'objets différents est sans importance, tant que les deux implémentent IEnumerable.


5
Enumerable.Empty <T> renvoie en fait un tableau vide de T (T [0]), avec l'avantage que le même tableau vide est réutilisé. Notez que cette approche n'est pas idéale pour les tableaux non vides, car les éléments peuvent être modifiés (cependant un tableau ne peut pas être redimensionné, le redimensionnement implique la création d'une nouvelle instance).
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>();
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.