389

Given the following code and the suggestions given in this question, I've decided to modify this original method and ask if there are any values in the IEnumarable return it, if not return an IEnumerable with no values.

Here is the method:

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

Since everything is inside the return statement, I don't know how I could do this. Would something like this work?

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

The above method doesn't work, and in fact it's not supposed to; I just feel it illustrates my intentions. I feel I should specify that the code doesn't work because you can't create an instance of an abstract class.

Here is the calling code, I don't want it to receive a null IEnumerable at any time:

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

Thank you for your time.

Selim Yildiz
  • 5,254
  • 6
  • 18
  • 28
Sergio Tapia
  • 40,006
  • 76
  • 183
  • 254

6 Answers6

663

You can use list ?? Enumerable.Empty<Friend>(), or have FindFriends return Enumerable.Empty<Friend>()

This can be found under the System.Linq namespace.

JohnLBevan
  • 22,735
  • 13
  • 96
  • 178
Michael Mrozek
  • 169,610
  • 28
  • 168
  • 175
  • 7
    Would it change things if he returned, say, `new List()` since it will be cast to `IEnumerable` when returned from that method? – Sarah Vessels Jul 12 '10 at 16:57
  • 82
    `new List()` is a more expensive operation because it would create an instance of a list (and allocate memory for it in the process) – Igor Pashchuk Jun 30 '11 at 20:14
  • Starting in 2015 (.NET Framework 4.6) you can also use `Array.Empty()` which has a bit fewer characters to type (in `System` namespace, not `System.Linq`). – Jeppe Stig Nielsen Feb 27 '23 at 11:44
193

You could return Enumerable.Empty<T>().

Brad Parks
  • 66,836
  • 64
  • 257
  • 336
LukeH
  • 263,068
  • 57
  • 365
  • 409
119

As for me, most elegant way is yield break

Lucius
  • 2,794
  • 4
  • 20
  • 42
Pavel Tupitsyn
  • 8,393
  • 3
  • 22
  • 44
  • 9
    But that's if you use yield return and such, isn't it? – Svish Jul 12 '10 at 15:28
  • 16
    +1 as his code correctly should use yield for the way he's working with IEnumerable – Chris Marisic Jul 12 '10 at 15:32
  • 6
    Pardon my ignorance on the subject, but could you please illustrate how to use yield break in this context? I've seen examples only in for loops but that doesn't paint a clear picture for me. – Sergio Tapia Jul 12 '10 at 15:34
  • Updated the answer with an example. Really is the most elegant way of doing it I would agree. :) – Johny Skovdal Jul 09 '15 at 12:24
  • 4
    Edit got rejected in peer review, so here's the example I was talking about @Pyritie - the formatting gets messed up though, so I added it to http://pastebin.com/X9Z49Vq1 as well: `public IEnumerable 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 Mar 31 '16 at 19:31
  • I know that I'm several years late, but I'm wondering if someone would comment on why using a yield statement is the "correct" way. It certainly doesn't appear "most elegant" to me since you would have to add a foreach statement just to be able to use the yield. What am I missing? – Ben Jasperson Nov 29 '22 at 17:33
9

That's of course only a matter of personal preference, but I'd write this function using yield return:

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
  • 111
  • 3
1

I think the simplest way would be

 return new Friend[0];

The requirements of the return are merely that the method return an object which implements IEnumerable<Friend>. The fact that under different circumstances you return two different kinds of objects is irrelevant, as long as both implement IEnumerable.

James Curran
  • 101,701
  • 37
  • 181
  • 258
  • 5
    Enumerable.Empty actually returns an empty array of T (T[0]), with the advantage that the same empty array is reused. Note that this approach is not ideal for non-empty arrays, because the elements can be modified (however an array can't be resized, resizing involves creating a new instance). – Francis Gagné Jul 12 '10 at 15:40
1
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
  • 551
  • 1
  • 7
  • 19
  • Using List for returning an empty Enumerable is wasting. Array.Empty() or Enumerable.Empty() are the most resource sparing solutions. In fact Enumerable.Empty() itself returns an empty array, see: https://github.com/microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs – CLS Sep 07 '22 at 13:15