Wie kann ich eine leere IEnumerable zurückgeben?

328

Angesichts des folgenden Codes und der in dieser Frage gegebenen Vorschläge habe ich beschlossen, diese ursprüngliche Methode zu ändern und zu fragen, ob Werte in IEnumarable vorhanden sind. Geben Sie sie zurück, wenn nicht, geben Sie eine IEnumerable ohne Werte zurück.

Hier ist die Methode:

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

Da sich alles in der return-Anweisung befindet, weiß ich nicht, wie ich das tun könnte. Würde so etwas funktionieren?

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

Die obige Methode funktioniert nicht und sollte es auch nicht. Ich fühle nur, dass es meine Absichten veranschaulicht. Ich denke, ich sollte angeben, dass der Code nicht funktioniert, da Sie keine Instanz einer abstrakten Klasse erstellen können.

Hier ist der aufrufende Code, ich möchte nicht, dass er zu irgendeinem Zeitpunkt eine Null-IEnumerable erhält:

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

        }

Vielen Dank für Ihre Zeit.

Sergio Tapia
quelle
2
Wenn Sie sich den Code hier ansehen, sollten Sie Yield Return und Yield Break verwenden.
Chris Marisic

Antworten:

574

Sie können verwenden list ?? Enumerable.Empty<Friend>()oder FindFriendszurückgebenEnumerable.Empty<Friend>()

Michael Mrozek
quelle
7
Würde es die Dinge ändern, wenn er zurückkehren würde, sagen wir, new List<Friend>()da es gegossen wird, IEnumerable<Friend>wenn es von dieser Methode zurückgegeben wird?
Sarah Vessels
73
new List<Friend>()ist eine teurere Operation, weil sie eine Instanz einer Liste erstellen würde (und dabei Speicher dafür zuweisen würde)
Igor Pashchuk
105

Für mich ist der eleganteste Weg yield break

Pavel Tupitsyn
quelle
8
Aber das ist, wenn Sie Ertragsrendite und so verwenden, nicht wahr?
Svish
15
+1 als sein Code sollte Ausbeute für die Art und Weise verwenden, wie er mit IEnumerable arbeitet
Chris Marisic
6
Verzeihen Sie meine Unwissenheit zu diesem Thema, aber können Sie bitte veranschaulichen, wie die Ertragsunterbrechung in diesem Zusammenhang verwendet wird? Ich habe nur Beispiele für for-Schleifen gesehen, aber das ergibt für mich kein klares Bild.
Sergio Tapia
Die Antwort wurde mit einem Beispiel aktualisiert. Wirklich ist die eleganteste Art, es zu tun, würde ich zustimmen. :)
Johny Skovdal
4
Bearbeiten wurde in Peer - Review abgelehnt, so ist hier das Beispiel , das ich sprach über @Pyritie - die Formatierung obwohl vermasselt wird, so dass ich es zu hinzugefügt pastebin.com/X9Z49Vq1 auch: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

Das ist natürlich nur eine Frage der persönlichen Präferenz, aber ich würde diese Funktion mit Yield Return schreiben:

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
                }
        }
    }
}
Chaos
quelle
1

Ich denke, der einfachste Weg wäre

 return new Friend[0];

Die Anforderungen der Rückgabe sind lediglich, dass die Methode ein Objekt zurückgibt, das implementiert wird IEnumerable<Friend>. Die Tatsache, dass Sie unter verschiedenen Umständen zwei verschiedene Arten von Objekten zurückgeben, ist irrelevant, solange beide IEnumerable implementieren.

James Curran
quelle
5
Enumerable.Empty <T> gibt tatsächlich ein leeres Array von T (T [0]) zurück, mit dem Vorteil, dass dasselbe leere Array wiederverwendet wird. Beachten Sie, dass dieser Ansatz nicht für nicht leere Arrays geeignet ist, da die Elemente geändert werden können (die Größe eines Arrays kann jedoch nicht geändert werden, bei der Größenänderung wird eine neue Instanz erstellt).
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>();
}
Natarajan Ganapathi
quelle