Bagaimana saya bisa mengembalikan IEnumerable yang kosong?

329

Dengan kode berikut dan saran yang diberikan dalam pertanyaan ini , saya telah memutuskan untuk memodifikasi metode asli ini dan bertanya apakah ada nilai dalam IEnumarable mengembalikannya, jika tidak mengembalikan IEnumerable tanpa nilai.

Inilah metodenya:

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

Karena semuanya ada di dalam pernyataan kembali, saya tidak tahu bagaimana saya bisa melakukan ini. Apakah sesuatu seperti ini berfungsi?

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

Metode di atas tidak bekerja, dan sebenarnya itu tidak seharusnya; Saya hanya merasa itu menggambarkan niat saya. Saya merasa saya harus menentukan bahwa kode tidak berfungsi karena Anda tidak dapat membuat turunan dari kelas abstrak.

Ini adalah kode panggilan, saya tidak ingin menerima IEnumerable nol kapan saja:

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

        }

Terima kasih atas waktu Anda.

Sergio Tapia
sumber
2
Melihat kode di sini Anda harus menggunakan imbal hasil dan penghentian produksi.
Chris Marisic

Jawaban:

575

Anda dapat menggunakan list ?? Enumerable.Empty<Friend>(), atau FindFriendskembaliEnumerable.Empty<Friend>()

Michael Mrozek
sumber
7
Apakah itu akan mengubah keadaan jika dia kembali, katakanlah, new List<Friend>()karena itu akan dilemparkan ke IEnumerable<Friend>ketika kembali dari metode itu?
Kapal Sarah
73
new List<Friend>()adalah operasi yang lebih mahal karena akan membuat turunan dari daftar (dan mengalokasikan memori untuknya dalam proses)
Igor Pashchuk
106

Bagi saya, cara yang paling elegan adalah yield break

Pavel Tupitsyn
sumber
8
Tapi itu jika Anda menggunakan imbal hasil dan semacamnya, bukan?
Svish
15
+1 sebagai kode dengan benar harus menggunakan hasil untuk cara dia bekerja dengan IEnumerable
Chris Marisic
6
Maafkan ketidaktahuan saya tentang masalah ini, tetapi bisakah Anda menggambarkan bagaimana cara menggunakan yield break dalam konteks ini? Saya telah melihat contoh hanya untuk loop tetapi itu tidak melukiskan gambaran yang jelas bagi saya.
Sergio Tapia
Memperbarui jawabannya dengan sebuah contoh. Benar-benar cara paling elegan untuk melakukannya, saya setuju. :)
Johny Skovdal
4
Edit ditolak di peer review, jadi inilah contoh yang saya bicarakan tentang @Pyritie - pemformatannya menjadi kacau, jadi saya menambahkannya ke pastebin.com/X9Z49Vq1 juga: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

Itu tentu saja hanya masalah preferensi pribadi, tapi saya akan menulis fungsi ini menggunakan imbal hasil:

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
                }
        }
    }
}
Kekacauan
sumber
1

Saya pikir cara paling sederhana adalah

 return new Friend[0];

Persyaratan pengembalian hanyalah bahwa metode mengembalikan objek yang mengimplementasikan IEnumerable<Friend>. Fakta bahwa dalam keadaan yang berbeda Anda mengembalikan dua jenis objek tidak relevan, selama keduanya mengimplementasikan IEnumerable.

James Curran
sumber
5
Enumerable.Empty <T> sebenarnya mengembalikan array kosong T (T [0]), dengan keuntungan bahwa array kosong yang sama digunakan kembali. Perhatikan bahwa pendekatan ini tidak ideal untuk array non-kosong, karena elemen dapat dimodifikasi (namun array tidak dapat diubah ukurannya, mengubah ukuran melibatkan membuat instance baru).
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
sumber