Как я могу вернуть пустой IEnumerable?

329

Учитывая следующий код и предложения, приведенные в этом вопросе , я решил изменить этот оригинальный метод и спросить, есть ли какие-либо значения в IEnumarable, вернуть его, если не вернуть IEnumerable без значений.

Вот метод:

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

Поскольку все находится внутри оператора return, я не знаю, как я мог это сделать. Будет ли что-то вроде этой работы?

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

Вышеупомянутый метод не работает, и фактически это не должно; Я просто чувствую, что это иллюстрирует мои намерения. Я чувствую, что должен указать, что код не работает, потому что вы не можете создать экземпляр абстрактного класса.

Вот код вызова, я не хочу, чтобы он получал нулевой IEnumerable в любое время:

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

        }

Спасибо за уделенное время.

Серхио Тапиа
источник
2
Глядя на код здесь, вы должны использовать yield return и yield break.
Крис Марисик

Ответы:

575

Вы можете использовать list ?? Enumerable.Empty<Friend>()или иметь FindFriendsвозвратEnumerable.Empty<Friend>()

Майкл Мрозек
источник
7
Изменит ли это что-то, если он вернется, скажем, new List<Friend>()так как он будет приведен к IEnumerable<Friend>при возвращении из этого метода?
Сара Весселс
73
new List<Friend>()является более дорогой операцией, потому что она создаст экземпляр списка (и выделит для него память в процессе)
Игорь Пащук
106

Как по мне, самый элегантный способ yield break

Павел Тупицын
источник
8
Но если вы используете доходность и тому подобное, не так ли?
Свиш
15
+1, так как его код должен правильно использовать yield для того, как он работает с IEnumerable
Крис Марисик
6
Прошу прощения за мое невежество по этому вопросу, но не могли бы вы проиллюстрировать, как использовать разрыв доходности в этом контексте? Я видел примеры только для циклов, но это не дает мне ясной картины.
Серхио Тапиа
Обновил ответ с примером. На самом деле это самый элегантный способ сделать это, я бы согласился. :)
Джонни Сковдал
4
Редактирование было отклонено в рецензировании, так что вот пример, о котором я говорил, @Pyritie - хотя форматирование испорчено, поэтому я также добавил его на 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; } }
Джонни Сковдал,
8

Это, конечно, только вопрос личных предпочтений, но я бы написал эту функцию, используя 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
                }
        }
    }
}
Хаос
источник
1

Я думаю, что самый простой способ был бы

 return new Friend[0];

Требования возврата состоят в том, что метод возвращает объект, который реализует IEnumerable<Friend>. Тот факт, что при разных обстоятельствах вы возвращаете два разных типа объектов, не имеет значения, поскольку оба реализуют IEnumerable.

Джеймс Керран
источник
5
Enumerable.Empty <T> фактически возвращает пустой массив T (T [0]), с тем преимуществом, что этот же пустой массив используется повторно. Обратите внимание, что этот подход не идеален для непустых массивов, потому что элементы могут быть изменены (однако размер массива не может быть изменен, изменение размера включает создание нового экземпляра).
Фрэнсис Гань
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>();
}
Натараджан Ганапати
источник