metode c # dengan params tanpa batas atau metode dengan array atau daftar?

21

Baru-baru ini saya mengetahui bahwa Anda dapat membuat beberapa metode dengan parameter tidak terbatas, misalnya:

SomeMethod(params int[] numbers);

tetapi pertanyaan saya adalah, apa perbedaan antara itu dan hanya membuat metode yang menerima daftar atau array?

SomeMethod(int[] numbers);
SomeMethod(List<int> numbers);

mungkin itu berdampak pada kinerja? Saya tidak sepenuhnya mengerti atau melihat dengan cara apa Anda lebih suka yang dengan parameter tidak terbatas.

Pencarian cepat di google tidak membantu, saya harap Anda bisa membantu saya.

Ricardo Sanchez Santos
sumber
Selain jawaban saya di bawah ini, paramsjuga membutuhkan jenis argumen menjadi array. Jika Anda perlu mengkonsumsi koleksi selain array, mungkin lebih masuk akal untuk memberikan paramsargumen.
digitlworld
1
@digitlworld: Jika topik ini menarik minat Anda, lihat github.com/dotnet/csharplang/issues/179 untuk diskusi.
Eric Lippert
Lihatlah tanda tangan dan / atau implementasi Console.Write.
3Dave

Jawaban:

27

apa perbedaan antara itu dan hanya membuat metode yang menerima daftar atau array?

Perbedaan antara

void M(params int[] x)

dan

void N(int[] x)

adalah M dapat disebut seperti ini:

M(1, 2, 3)

atau seperti ini:

M(new int[] { 1, 2, 3 });

tetapi N hanya bisa dipanggil dengan cara kedua , bukan cara pertama .

mungkin itu berdampak pada kinerja?

Dampaknya terhadap kinerja adalah apakah Anda menelepon M dengan cara pertama atau cara kedua, baik cara Anda membuat array dibuat. Membuat array memiliki dampak kinerja karena membutuhkan waktu dan memori. Ingatlah bahwa dampak kinerja harus diukur terhadap sasaran kinerja; tidak mungkin bahwa biaya menciptakan array tambahan adalah faktor gating yang merupakan perbedaan antara keberhasilan dan kegagalan di pasar.

Saya tidak sepenuhnya mengerti atau melihat dengan cara apa Anda lebih suka yang dengan parameter tidak terbatas.

Ini murni dan sepenuhnya merupakan kemudahan bagi pembuat kode yang memanggil metode; hanya lebih pendek dan lebih mudah untuk ditulis

M(1, 2, 3);

alih-alih menulis

M(new int[] { 1, 2, 3 });

Ini hanya menghemat beberapa penekanan tombol di sisi pemanggil. Itu semuanya.

Beberapa pertanyaan yang tidak Anda tanyakan tetapi mungkin ingin tahu jawabannya:

Apa sebutan fitur ini?

Metode yang memungkinkan sejumlah variabel argumen untuk dilewatkan di sisi pemanggil disebut variadic . Metode Params adalah bagaimana C # mengimplementasikan metode variadic.

Bagaimana cara kerja resolusi berlebihan dengan metode variadic?

Ketika dihadapkan dengan masalah resolusi kelebihan beban, C # akan mempertimbangkan bentuk "normal" dan "diperluas", dan bentuk "normal" selalu menang jika keduanya berlaku. Sebagai contoh, pertimbangkan ini:

void P(params object[] x){}

dan kami memiliki panggilan

P(null);

Ada dua kemungkinan yang berlaku. Dalam bentuk "normal", kami memanggil Pdan meneruskan referensi nol untuk array. Dalam formulir "diperluas", kami menyebutnya P(new object[] { null }). Dalam hal ini, bentuk normal menang. Jika kami menerima panggilan P(null, null)maka formulir normal tidak dapat diterapkan dan formulir yang diperluas akan menang secara default.

Tantangan : Misalkan kita memiliki var s = new[] { "hello" };dan menelepon P(s);. Jelaskan apa yang terjadi di situs panggilan dan mengapa. Anda mungkin akan terkejut!

Tantangan : Misalkan kita memiliki keduanya void P(object x){}dan void P(params object[] x){}. Apa yang P(null)dilakukan, dan mengapa?

Tantangan : Misalkan kita memiliki keduanya void M(string x){}dan void M(params string[] x){}. Apa yang M(null)dilakukan, dan mengapa? Bagaimana ini berbeda dari kasus sebelumnya?

Eric Lippert
sumber
Ch2: P(null)vs. P((object)null)vs. P((object[])null)- di mana saya bisa menemukan penjelasan untuk perbedaan ini? Rasanya seperti nullmemiliki beberapa tipe khusus , yang mengkonversi ke array daripada objek ( P(null)), tetapi menemukan konversi ke string atau array string ambigu ( M(null)) ... yang terasa sangat aneh, akan mengharapkannya menjadi ambigu dalam kedua kasus atau memilih versi arg tunggal (yang tidak). Tapi saya kira ini lebih tentang paramsmenjadi generik , seperti referensi universal ( &&) dalam template C ++, dan dengan demikian lebih cocok (dalam Ch2, bukan di Ch3).
firda
@firda: Anda dapat menemukan penjelasan dalam spesifikasi C #. Alasan untuk keanehan adalah: null dapat dikonversi ke objek, string, objek [] dan string []. Jadi pertanyaan yang kemudian diajukan kepada resolusi berlebihan adalah: konversi mana yang terbaik ? Aturan pengendalian dalam hal ini spesifik lebih baik daripada umum . Bagaimana kita tahu tipe mana yang lebih spesifik? Aturannya adalah: semua jerapah adalah hewan tetapi tidak semua hewan jerapah, oleh karena itu, jerapah lebih spesifik daripada hewan. Semua object[]yang object, tapi tidak semua objectyang object[], karena object[]lebih spesifik.
Eric Lippert
@ Firda: Sekarang Anda tahu mengapa string bersifat mendua. Hal ini tidak benar bahwa "semua string[]yang string." Bahkan TIDAK string[]ada stringdan TIDAK stringada string[], jadi stringtidak lebih spesifik atau lebih umum daripada string[], dan kami mendapatkan kesalahan ambiguitas ketika diminta untuk memilih.
Eric Lippert
Semua object[]yang object... object[]lebih spesifik sehingga P(null)berlaku untuk array yang lebih spesifik, thx, itulah yang saya hilang. Menemukan beberapa aturan di sini: docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
firda
5

Baru saja melakukan prototipe kecil. Jawabannya paramsadalah gula sintaksis untuk melewatkan dalam array. Itu tidak terlalu mengejutkan. Saya membuat dua versi dari metode yang sama, di mana satu-satunya perbedaan adalah kata kunci "params". IL yang dihasilkan untuk keduanya identik, kecuali bahwa a System.ParamArrayAttributediterapkan pada paramsversi.

Lebih lanjut, IL yang dihasilkan di situs panggilan juga sama antara saya memanggil metode dengan yang dinyatakan secara manual new int[]dan memanggil metode hanya menggunakan paramsargumen.

Jadi, jawabannya sepertinya "kenyamanan". Tampaknya tidak ada perbedaan dalam kinerja. Anda juga dapat memanggil paramsfungsi dengan array, jadi itu juga tidak terlalu mengejutkan. Turun ke jika pengguna metode Anda lebih mudah untuk memanggilnya dengan sejumlah parameter (misalnya someMethod(1, 2, 3)) daripada harus selalu membuat koleksi terlebih dahulu (misalnya someMethod(new List<int>() { 1, 2, 3 } )).

digitlworld
sumber
4

Fitur parameter tak terbatas menawarkan manfaat berikut dalam banyak skenario:

  1. Kopling longgar
  2. Dapat digunakan kembali yang disempurnakan
  3. Kinerja aplikasi secara keseluruhan lebih baik

Berikut adalah contoh di mana opsi parameter tak terbatas adalah pilihan yang bagus

Pertimbangkan bahwa aplikasi untuk mengirim email perlu dibangun.

Fungsi yang mengirim email harus dapat menangani nilai tunggal atau ganda untuk bidang 'Ke', 'CC' dan 'BCC'.

Jika jenis parameter ditetapkan menjadi array atau daftar untuk semua bidang (Ke, CC, BCC), maka fungsi panggilan akan dipaksa untuk berurusan dengan semua kerumitan mendefinisikan 3 array atau daftar untuk memanggil fungsi pengirim email .

Bahkan jika pemanggil ingin mengirim email hanya ke satu alamat, fungsi pengirim email akan memaksa pemanggil untuk menentukan dan mengirim 3 array yang berbeda sebagai parameter.

Jika fungsi pengirim email mengambil pendekatan params tidak terbatas, maka fungsi pemanggil tidak perlu berurusan dengan semua kompleksitas.

Pendekatan parameter tak terbatas berkontribusi pada kinerja runtime aplikasi yang lebih baik dengan menghindari pembuatan array atau daftar di mana pun tidak perlu.

Gopinath
sumber
2

Dari perspektif non-kinerja , gaya, paramskata kunci sangat baik untuk dimiliki ketika Anda ingin mengirim daftar parameter opsional.

Secara pribadi, saya akan menggunakan paramsketika kode saya seperti

SomeMethod('Option1', 'Option17');

void SomeMethod(params string[] options)
{
    foreach(var option in options)
    {
        switch(option): ...
    }
}

Bagian yang menyenangkan tentang ini adalah saya dapat menggunakan metode ini di semua tempat tanpa harus membuat array atau daftar setiap waktu.

Saya akan menggunakan arrayatau listketika saya tahu saya akan selalu melewati fungsi ini satu set data yang sudah disatukan seperti

List<User> users = GetUsersFromDB();
SomeMethod(users);

Saya melihat manfaat dari paramsfleksibilitas yang ditambahkannya. Ini mungkin dampak yang relatif kecil untuk kode Anda, tetapi masih merupakan alat yang bagus untuk memilikinya.

OliveJuice
sumber
1

Konvensi panggilan berbeda. Sebagai contoh ...

public class Test
{
    public void Method1( params int[] nums )
    {
        nums.ToList().ForEach( n => Console.WriteLine(n) );
    }

    public void Method2( List<int> nums )
    {
        nums.ForEach( n  => Console.WriteLine(n) );
    }   
}

void Main()
{   
    var t = new Test();
    t.Method1( 1, 2, 3, 4 );
    t.Method2( new List<int>() { 1, 2, 3, 4 } );
}

Dalam kasus pertama, Anda dapat mengirimkan sebanyak int sebagai parameter terpisah ke metode. Pada yang kedua, Anda perlu membuat instance daftar dan meneruskannya.

JP Alioto
sumber