Melewati satu item sebagai IEnumerable <T>

377

Apakah ada cara umum untuk mengirimkan satu item bertipe Tke metode yang mengharapkan IEnumerable<T>parameter? Bahasa adalah C #, framework versi 2.0.

Saat ini saya menggunakan metode helper (ini. Net 2.0, jadi saya memiliki sejumlah metode casting / projecting helper yang mirip dengan LINQ), tetapi ini sepertinya konyol:

public static class IEnumerableExt
{
    // usage: IEnumerableExt.FromSingleItem(someObject);
    public static IEnumerable<T> FromSingleItem<T>(T item)
    {
        yield return item; 
    }
}

Cara lain tentu saja adalah dengan membuat dan mengisi a List<T>atau a Arraydan meneruskannya daripada IEnumerable<T>.

[Sunting] Sebagai metode ekstensi itu mungkin dinamai:

public static class IEnumerableExt
{
    // usage: someObject.SingleItemAsEnumerable();
    public static IEnumerable<T> SingleItemAsEnumerable<T>(this T item)
    {
        yield return item; 
    }
}

Apakah saya melewatkan sesuatu di sini?

[Sunting2] Kami menemukan someObject.Yield()(seperti yang disarankan @Peter dalam komentar di bawah) sebagai nama terbaik untuk metode ekstensi ini, terutama untuk singkatnya, jadi di sini beserta komentar XML jika ada yang ingin mengambilnya:

public static class IEnumerableExt
{
    /// <summary>
    /// Wraps this object instance into an IEnumerable&lt;T&gt;
    /// consisting of a single item.
    /// </summary>
    /// <typeparam name="T"> Type of the object. </typeparam>
    /// <param name="item"> The instance that will be wrapped. </param>
    /// <returns> An IEnumerable&lt;T&gt; consisting of a single item. </returns>
    public static IEnumerable<T> Yield<T>(this T item)
    {
        yield return item;
    }
}
Groo
sumber
6
Saya akan membuat sedikit modifikasi dalam tubuh metode ekstensi: if (item == null) yield break; Sekarang Anda berhenti dari melewati nol serta mengambil keuntungan dari pola objek nol (sepele) untuk IEnumerable. ( foreach (var x in xs)menangani kosong xssaja). Kebetulan, fungsi ini adalah unit monadik untuk daftar monad itu IEnumerable<T>, dan mengingat cinta-fest monad di Microsoft saya terkejut sesuatu seperti ini tidak dalam kerangka di tempat pertama.
Matt Enright
2
Untuk metode ekstensi, Anda tidak boleh menamainya AsEnumerablekarena ekstensi bawaan dengan nama itu sudah ada . (Ketika Tmengimplementasikan IEnumerable, misalnya string,.)
Jon-Eric
22
Bagaimana dengan penamaan metode Yield? Tidak ada yang mengalahkan singkatnya.
Philip Guin
4
Memberi saran di sini. "SingleItemAsEnumerable" sedikit bertele-tele. "Yield" menggambarkan implementasi daripada antarmuka - yang tidak baik. Untuk nama yang lebih baik, saya sarankan "AsSingleton", yang sesuai dengan arti sebenarnya dari perilaku tersebut.
Earth Engine
4
Saya benci left==nullcek di sini. Itu merusak keindahan kode dan menghentikan kode menjadi lebih fleksibel - bagaimana jika suatu hari nanti Anda perlu menghasilkan singleton dengan sesuatu yang bisa nol? Maksud saya, new T[] { null }tidak sama dengan new T[] {}, dan suatu hari Anda mungkin perlu membedakan mereka.
Earth Engine

Jawaban:

100

Metode pembantu Anda adalah cara terbersih untuk melakukannya, IMO. Jika Anda memasukkan daftar atau array, maka sepotong kode yang tidak bermoral dapat membuangnya dan mengubah isinya, menyebabkan perilaku aneh dalam beberapa situasi. Anda bisa menggunakan koleksi read-only, tetapi itu kemungkinan akan melibatkan lebih banyak pembungkus. Saya pikir solusi Anda serapi itu.

Jon Skeet
sumber
baik jika daftar / array dibangun ad-hoc, cakupannya berakhir setelah pemanggilan metode, jadi seharusnya tidak menyebabkan masalah
Mario F
Jika dikirim sebagai array, bagaimana bisa diubah? Saya kira itu bisa dilemparkan ke array, dan kemudian mengubah referensi ke sesuatu yang lain, tetapi apa gunanya itu? (Saya mungkin melewatkan sesuatu ...)
Svish
2
Misalkan Anda memutuskan untuk membuat satu enumerable untuk meneruskan ke dua metode yang berbeda ... lalu yang pertama melemparkannya ke sebuah array dan mengubah isinya. Anda kemudian meneruskannya sebagai argumen ke metode lain, tidak menyadari perubahan tersebut. Saya tidak mengatakan itu mungkin, hanya saja memiliki sesuatu yang bisa berubah ketika tidak perlu menjadi kurang rapi daripada naturla immutability.
Jon Skeet
3
Ini adalah jawaban yang diterima, dan kemungkinan besar akan dibaca, jadi saya akan menambahkan kekhawatiran saya di sini. Saya mencoba metode ini, tapi itu mematahkan panggilan kompilasi saya sebelumnya ke myDict.Keys.AsEnumerable()tempat myDictbertipe Dictionary<CheckBox, Tuple<int, int>>. Setelah saya mengganti nama metode ekstensi menjadi SingleItemAsEnumerable, semuanya mulai berfungsi. Tidak dapat mengonversi IEnumerable <Kamus <Kotak centang, System.Tuple <int, int >>. KeyCollection> 'ke' IEnumerable <CheckBox> '. Konversi eksplisit ada (apakah Anda melewatkan gips?) Saya dapat hidup dengan peretasan untuk sementara waktu, tetapi bisakah peretas daya lainnya menemukan cara yang lebih baik?
Hamish Grubijan
3
@ HamishGrubijan: Sepertinya Anda baru saja ingin dictionary.Valuesmemulai. Pada dasarnya tidak jelas apa yang terjadi, tetapi saya sarankan Anda memulai pertanyaan baru tentang hal itu.
Jon Skeet
133

Nah, jika metode mengharapkan IEnumerableAnda harus melewati sesuatu yang merupakan daftar, bahkan jika itu berisi satu elemen saja.

lewat

new[] { item }

sebagai argumen harus cukup saya pikir

Mario F
sumber
32
Saya pikir Anda bahkan mungkin menjatuhkan T, karena akan disimpulkan (kecuali saya sangat salah di sini: p)
Svish
2
Saya pikir itu tidak disimpulkan dalam C # 2.0.
Groo
4
"Bahasa adalah C #, versi kerangka 2" Kompiler C # 3 dapat menyimpulkan T, dan kode akan sepenuhnya kompatibel dengan. NET 2.
sisve
jawaban terbaik ada di bagian bawah ?!
Falco Alexander
2
@Svish Saya menyarankan dan mengedit jawaban untuk melakukan hal itu - kita berada di tahun 2020 sekarang, jadi itu seharusnya imho "standar"
OschtärEi
120

Di C # 3.0 Anda dapat memanfaatkan kelas System.Linq.Enumerable:

// using System.Linq

Enumerable.Repeat(item, 1);

Ini akan membuat IEnumerable baru yang hanya berisi item Anda.

luksan
sumber
26
Saya pikir solusi ini akan membuat kode lebih sulit dibaca. :( Ulangi pada satu elemen cukup kontra-intuitif bukan?
Drahakar
6
Ulangi sekali membaca ok untuk saya. Solusi yang jauh lebih sederhana tanpa harus khawatir menambahkan metode ekstensi lain, dan memastikan namespace disertakan di mana pun Anda ingin menggunakannya.
si618
13
Ya saya sebenarnya hanya menggunakan new[]{ item }diri saya sendiri, saya hanya berpikir itu adalah solusi yang menarik.
luksan
7
Solusi ini adalah uang.
ProVega
IMHO ini harus menjadi jawaban yang diterima. Mudah dibaca, ringkas, dan diimplementasikan dalam satu baris pada BCL, tanpa metode ekstensi khusus.
Ryan
35

Dalam C # 3 (saya tahu Anda mengatakan 2), Anda dapat menulis metode ekstensi generik yang mungkin membuat sintaks sedikit lebih dapat diterima:

static class IEnumerableExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this T item)
    {
        yield return item;
    }
}

kode klien kemudian item.ToEnumerable().

Ðаn
sumber
Terima kasih, saya menyadari hal itu (berfungsi di. Net 2.0 jika saya menggunakan C # 3.0), saya hanya ingin tahu apakah ada mekanisme bawaan untuk ini.
Groo
12
Ini adalah alternatif yang sangat bagus. Saya hanya ingin menyarankan penggantian nama ToEnumerableuntuk menghindari kekacauanSystem.Linq.Enumerable.AsEnumerable
Fede
3
Sebagai catatan, sudah ada ToEnumerablemetode ekstensi untuk IObservable<T>, jadi nama metode ini juga mengganggu konvensi yang ada. Jujur, saya sarankan tidak menggunakan metode ekstensi sama sekali, hanya karena terlalu generik.
cwharris
14

Metode pembantu ini berfungsi untuk item atau banyak.

public static IEnumerable<T> ToEnumerable<T>(params T[] items)
{
    return items;
}    
durhaka
sumber
1
Variasi yang berguna, karena mendukung lebih dari satu item. Saya suka itu bergantung paramsuntuk membangun array, jadi kode yang dihasilkan tampak bersih. Belum memutuskan apakah saya suka kurang lebih new T[]{ item1, item2, item3 };untuk beberapa item.
ToolmakerSteve
Pintar ! Menyukainya
Mitsuru Furuta
10

Saya agak terkejut bahwa tidak ada yang menyarankan kelebihan baru dari metode dengan argumen tipe T untuk menyederhanakan API klien.

public void DoSomething<T>(IEnumerable<T> list)
{
    // Do Something
}

public void DoSomething<T>(T item)
{
    DoSomething(new T[] { item });
}

Sekarang kode klien Anda bisa melakukan ini:

MyItem item = new MyItem();
Obj.DoSomething(item);

atau dengan daftar:

List<MyItem> itemList = new List<MyItem>();
Obj.DoSomething(itemList);
Joshua Starner
sumber
19
Bahkan lebih baik, Anda bisa memiliki DoSomething<T>(params T[] items)yang berarti kompiler akan menangani konversi dari satu item ke array. (Ini juga akan memungkinkan Anda untuk mengirimkan beberapa item terpisah dan, sekali lagi, kompiler akan menangani mengonversinya menjadi sebuah array untuk Anda.)
LukeH
7

Baik (seperti yang telah dikatakan sebelumnya)

MyMethodThatExpectsAnIEnumerable(new[] { myObject });

atau

MyMethodThatExpectsAnIEnumerable(Enumerable.Repeat(myObject, 1));

Sebagai catatan tambahan, versi terakhir juga bisa menyenangkan jika Anda menginginkan daftar kosong objek anonim, mis

var x = MyMethodThatExpectsAnIEnumerable(Enumerable.Repeat(new { a = 0, b = "x" }, 0));
erikkallen
sumber
Terima kasih, meskipun Enumerable.Repeat baru di .Net 3.5. Tampaknya berperilaku mirip dengan metode pembantu di atas.
Groo
7

Seperti yang baru saja saya temukan, dan melihat bahwa pengguna LukeH menyarankan juga, cara sederhana yang bagus untuk melakukan ini adalah sebagai berikut:

public static void PerformAction(params YourType[] items)
{
    // Forward call to IEnumerable overload
    PerformAction(items.AsEnumerable());
}

public static void PerformAction(IEnumerable<YourType> items)
{
    foreach (YourType item in items)
    {
        // Do stuff
    }
}

Pola ini akan memungkinkan Anda untuk memanggil fungsi yang sama dalam banyak cara: satu item; banyak item (dipisahkan koma); sebuah array; sebuah daftar; enumerasi, dll.

Saya tidak 100% yakin pada efisiensi menggunakan metode AsEnumerable, tetapi itu berhasil.

Pembaruan: Fungsi AsEnumerable terlihat sangat efisien! ( referensi )

teppicymon
sumber
Sebenarnya, Anda tidak perlu .AsEnumerable()sama sekali. Array YourType[]sudah mengimplementasikan IEnumerable<YourType>. Tetapi pertanyaan saya merujuk pada kasus ketika hanya metode kedua (dalam contoh Anda) tersedia, dan Anda menggunakan .NET 2.0, dan Anda ingin mengirimkan satu item.
Groo
2
Ya, memang, tetapi Anda akan menemukan Anda mungkin mendapatkan stack overflow ;-)
teppicymon
Dan untuk benar-benar menjawab pertanyaan Anda yang sebenarnya (bukan yang sebenarnya ingin saya jawab sendiri!), Ya Anda cukup banyak mengubahnya menjadi array sesuai jawaban Mario
teppicymon
2
Bagaimana kalau hanya mendefinisikan suatu IEnumerable<T> MakeEnumerable<T>(params T[] items) {return items;}metode? Seseorang kemudian dapat menggunakannya dengan apa pun yang diharapkan IEnumerable<T>, untuk sejumlah item diskrit. Kode dasarnya harus seefisien mendefinisikan kelas khusus untuk mengembalikan satu item.
supercat
6

Walaupun itu terlalu banyak untuk satu metode, saya percaya beberapa orang mungkin menemukan Ekstensi Interaktif berguna.

Ekstensi Interaktif (Ix) dari Microsoft mencakup metode berikut.

public static IEnumerable<TResult> Return<TResult>(TResult value)
{
    yield return value;
}

Yang bisa dimanfaatkan seperti:

var result = EnumerableEx.Return(0);

Ix menambahkan fungsionalitas baru yang tidak ditemukan dalam metode ekstensi Linq asli, dan merupakan hasil langsung dari menciptakan Ekstensi Reaktif (Rx).

Pikirkan, Linq Extension Methods+ Ix= Rxuntuk IEnumerable.

Anda dapat menemukan Rx dan Ix di CodePlex .

cwharris
sumber
5

Ini 30% lebih cepat daripada yieldatau Enumerable.Repeatketika digunakan foreachkarena optimisasi kompiler C # ini , dan kinerja yang sama dalam kasus lain.

public struct SingleSequence<T> : IEnumerable<T> {
    public struct SingleEnumerator : IEnumerator<T> {
        private readonly SingleSequence<T> _parent;
        private bool _couldMove;
        public SingleEnumerator(ref SingleSequence<T> parent) {
            _parent = parent;
            _couldMove = true;
        }
        public T Current => _parent._value;
        object IEnumerator.Current => Current;
        public void Dispose() { }

        public bool MoveNext() {
            if (!_couldMove) return false;
            _couldMove = false;
            return true;
        }
        public void Reset() {
            _couldMove = true;
        }
    }
    private readonly T _value;
    public SingleSequence(T value) {
        _value = value;
    }
    public IEnumerator<T> GetEnumerator() {
        return new SingleEnumerator(ref this);
    }
    IEnumerator IEnumerable.GetEnumerator() {
        return new SingleEnumerator(ref this);
    }
}

dalam tes ini:

    // Fastest among seqs, but still 30x times slower than direct sum
    // 49 mops vs 37 mops for yield, or c.30% faster
    [Test]
    public void SingleSequenceStructForEach() {
        var sw = new Stopwatch();
        sw.Start();
        long sum = 0;
        for (var i = 0; i < 100000000; i++) {
            foreach (var single in new SingleSequence<int>(i)) {
                sum += single;
            }
        }
        sw.Stop();
        Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds}");
        Console.WriteLine($"Mops {100000.0 / sw.ElapsedMilliseconds * 1.0}");
    }
VB
sumber
Terima kasih, masuk akal untuk membuat struct untuk kasus ini untuk mengurangi beban GC di loop ketat.
Groo
1
Baik enumerator dan enumerable akan mendapatkan kotak ketika kembali ....
Stephen Drew
2
Jangan bandingkan menggunakan Stopwatch. Gunakan Benchmark.NET github.com/dotnet/BenchmarkDotNet
NN_
1
Hanya mengukurnya dan new [] { i }opsi sekitar 3,2 kali lebih cepat dari opsi Anda. Juga pilihan Anda sekitar 1,2 kali lebih cepat daripada ekstensi dengan yield return.
lorond
Anda dapat mempercepat ini dengan menggunakan optimisasi kompiler C # lain: tambahkan metode SingleEnumerator GetEnumerator()yang mengembalikan struct Anda. Compiler C # akan menggunakan metode ini (terlihat melalui mengetik bebek) daripada yang antarmuka dan dengan demikian menghindari tinju. Banyak koleksi bawaan memanfaatkan trik ini, seperti Daftar . Catatan: ini hanya akan berfungsi ketika Anda memiliki referensi langsung SingleSequence, seperti pada contoh Anda. Jika Anda menyimpannya dalam sebuah IEnumerable<>variabel maka triknya tidak akan berfungsi (metode antarmuka akan digunakan)
enzi
5

IanG memiliki postingan yang bagus tentang topik tersebut , menyarankan EnumerableFrom()sebagai nama (dan menyebutkan bahwa Haskell dan Rx menyebutnya Return). IIRC F # menyebutnya Kembali juga . F # Seqmemanggil operatorsingleton<'T> .

Menggoda jika Anda siap menjadi C #-sentris adalah menyebutnya Yield[menyinggung orang yang yield returnterlibat dalam mewujudkannya].

Jika Anda tertarik pada aspek perf, James Michael Hare memiliki nol pengembalian atau satu pos juga yang layak untuk dipindai.

Ruben Bartelink
sumber
4

Ini mungkin tidak lebih baik tetapi agak keren:

Enumerable.Range(0, 1).Select(i => item);
Ken Lange
sumber
Ini bukan. Ini berbeda.
nawfal
Ewww. Itu banyak detail, hanya untuk mengubah item menjadi enumerable.
ToolmakerSteve
1
Ini setara dengan menggunakan mesin Rube Goldberg untuk membuat sarapan. Ya itu berhasil, tetapi itu melompat melalui 10 lingkaran untuk sampai ke sana. Hal sederhana seperti ini bisa menjadi hambatan kinerja ketika dilakukan dalam loop ketat yang dijalankan jutaan kali. Dalam praktiknya, aspek kinerja tidak masalah dalam 99% kasus, tetapi secara pribadi saya masih berpikir itu terlalu berlebihan yang tidak perlu.
enzi
4

Saya setuju dengan komentar @ EarthEngine ke posting asli, yaitu 'AsSingleton' adalah nama yang lebih baik. Lihat entri wikipedia ini . Kemudian mengikuti dari definisi singleton bahwa jika nilai nol dilewatkan sebagai argumen bahwa 'AsSingleton' harus mengembalikan IEnumerable dengan nilai nol tunggal, bukan IEnumerable kosong yang akan menyelesaikan if (item == null) yield break;perdebatan. Saya pikir solusi terbaik adalah memiliki dua metode: 'AsSingleton' dan 'AsSingletonOrEmpty'; di mana, jika null dilewatkan sebagai argumen, 'AsSingleton' akan mengembalikan nilai nol tunggal dan 'AsSingletonOrEmpty' akan mengembalikan IEnumerable yang kosong. Seperti ini:

public static IEnumerable<T> AsSingletonOrEmpty<T>(this T source)
{
    if (source == null)
    {
        yield break;
    }
    else
    {
        yield return source;
    }
}

public static IEnumerable<T> AsSingleton<T>(this T source)
{
    yield return source;
}

Kemudian, ini akan, lebih atau kurang, analog dengan metode ekstensi 'First' dan 'FirstOrDefault' pada IEnumerable yang terasa benar.

Jason Boyd
sumber
2

Cara termudah yang saya katakan adalah new T[]{item};; tidak ada sintaks untuk melakukan ini. Setara terdekat yang dapat saya pikirkan adalah paramskata kunci, tetapi tentu saja yang mengharuskan Anda memiliki akses ke definisi metode dan hanya dapat digunakan dengan array.

FacticiusVir
sumber
2
Enumerable.Range(1,1).Select(_ => {
    //Do some stuff... side effects...
    return item;
});

Kode di atas berguna ketika menggunakan suka

var existingOrNewObject = MyData.Where(myCondition)
       .Concat(Enumerable.Range(1,1).Select(_ => {
           //Create my object...
           return item;
       })).Take(1).First();

Dalam cuplikan kode di atas tidak ada cek kosong / nol, dan dijamin hanya ada satu objek yang dikembalikan tanpa takut akan pengecualian. Lebih lanjut, karena malas, penutupan tidak akan dilaksanakan sampai terbukti tidak ada data yang sesuai dengan kriteria.

frhack
sumber
Jawaban ini secara otomatis ditandai "kualitas rendah". Seperti dijelaskan dalam bantuan ("Brevity dapat diterima, tetapi penjelasan yang lebih lengkap lebih baik."), Harap edit untuk memberi tahu OP apa yang dia lakukan salah, tentang apa kode Anda.
Sandra Rossi
Saya melihat sebagian besar jawaban ini, termasuk bagian yang saya tanggapi, diedit kemudian oleh orang lain. tetapi jika maksud dari potongan kedua adalah untuk memberikan nilai default jika MyData.Where(myCondition)kosong, itu sudah mungkin (dan sederhana) dengan DefaultIfEmpty(): var existingOrNewObject = MyData.Where(myCondition).DefaultIfEmpty(defaultValue).First();. Itu dapat lebih disederhanakan var existingOrNewObject = MyData.FirstOrDefault(myCondition);jika Anda inginkan default(T)dan bukan nilai khusus.
BACON
0

Saya agak terlambat ke pesta, tapi saya tetap akan berbagi jalan. Masalah saya adalah bahwa saya ingin mengikat ItemSource atau WPF TreeView ke objek tunggal. Hirarki terlihat seperti ini:

Proyek> Plot (s)> Kamar

Selalu akan ada hanya satu Proyek tetapi saya masih ingin Tampilkan proyek di Pohon, tanpa harus melewati Koleksi dengan hanya satu objek di dalamnya seperti beberapa yang disarankan.
Karena Anda hanya dapat melewatkan objek IEnumerable sebagai ItemSource, saya memutuskan untuk membuat kelas IEnumerable saya:

public class ProjectClass : IEnumerable<ProjectClass>
{
    private readonly SingleItemEnumerator<AufmassProjekt> enumerator;

    ... 

    public IEnumerator<ProjectClass > GetEnumerator() => this.enumerator;

    IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}

Dan buat Enumerator saya sendiri sesuai:

public class SingleItemEnumerator : IEnumerator
{
    private bool hasMovedOnce;

    public SingleItemEnumerator(object current)
    {
        this.Current = current;
    }

    public bool MoveNext()
    {
        if (this.hasMovedOnce) return false;
        this.hasMovedOnce = true;
        return true;
    }

    public void Reset()
    { }

    public object Current { get; }
}

public class SingleItemEnumerator<T> : IEnumerator<T>
{
    private bool hasMovedOnce;

    public SingleItemEnumerator(T current)
    {
        this.Current = current;
    }

    public void Dispose() => (this.Current as IDisposable).Dispose();

    public bool MoveNext()
    {
        if (this.hasMovedOnce) return false;
        this.hasMovedOnce = true;
        return true;
    }

    public void Reset()
    { }

    public T Current { get; }

    object IEnumerator.Current => this.Current;
}

Ini mungkin bukan solusi "terbersih" tetapi itu berhasil untuk saya.

EDIT
Untuk menegakkan prinsip tanggung jawab tunggal seperti yang ditunjukkan @Groo, saya membuat kelas pembungkus baru:

public class SingleItemWrapper : IEnumerable
{
    private readonly SingleItemEnumerator enumerator;

    public SingleItemWrapper(object item)
    {
        this.enumerator = new SingleItemEnumerator(item);
    }

    public object Item => this.enumerator.Current;

    public IEnumerator GetEnumerator() => this.enumerator;
}

public class SingleItemWrapper<T> : IEnumerable<T>
{
    private readonly SingleItemEnumerator<T> enumerator;

    public SingleItemWrapper(T item)
    {
        this.enumerator = new SingleItemEnumerator<T>(item);
    }

    public T Item => this.enumerator.Current;

    public IEnumerator<T> GetEnumerator() => this.enumerator;

    IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}

Yang saya gunakan seperti ini

TreeView.ItemSource = new SingleItemWrapper(itemToWrap);

EDIT 2
Saya memperbaiki kesalahan dengan MoveNext()metode ini.

IDarkCoder
sumber
The SingleItemEnumerator<T>kelas masuk akal, tapi membuat kelas "item tunggal IEnumerabledari dirinya sendiri" tampaknya seperti pelanggaran terhadap prinsip tanggung jawab tunggal. Mungkin itu membuatnya lebih praktis, tetapi saya masih lebih suka membungkusnya sesuai kebutuhan.
Groo
0

Untuk diajukan di bawah "Tidak selalu solusi yang baik , tetapi masih ... solusi" atau "Trik LINQ bodoh", Anda dapat menggabungkan Enumerable.Empty<>()dengan Enumerable.Append<>()...

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Append("Hello, World!");

... atau Enumerable.Prepend<>()...

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Prepend("Hello, World!");

Dua metode terakhir tersedia sejak .NET Framework 4.7.1 dan .NET Core 1.0.

Ini adalah solusi yang bisa diterapkan jika satu orang benar-benar berniat menggunakan metode yang ada alih-alih menulis mereka sendiri, meskipun aku ragu-ragu jika ini lebih atau kurang jelas dibandingkan dengan Enumerable.Repeat<>()solusi . Ini jelas merupakan kode yang lebih panjang (sebagian karena tipe inference parameter tidak dimungkinkanEmpty<>() ) dan membuat objek enumerator dua kali lebih banyak.

Akhiri ini dengan "Anda tahu metode ini ada?" jawabannya, Array.Empty<>()bisa diganti Enumerable.Empty<>(), tetapi sulit untuk berdebat yang membuat situasi ... lebih baik.

DAGING BABI ASAP
sumber
0

Saya baru-baru ini menanyakan hal yang sama pada posting lain ( Apakah ada cara untuk memanggil metode C # yang membutuhkan IEnumerable <T> dengan nilai tunggal? ... dengan benchmarking ).

Saya ingin orang-orang mampir di sini untuk melihat perbandingan benchmark singkat yang ditunjukkan di pos baru untuk 4 pendekatan yang disajikan dalam jawaban ini.

Tampaknya hanya menulis new[] { x }dalam argumen untuk metode ini adalah solusi terpendek dan tercepat.

mattica
sumber