Mengapa menggunakan kata kunci params?

336

Saya tahu ini adalah pertanyaan mendasar, tetapi saya tidak dapat menemukan jawaban.

Kenapa menggunakannya? jika Anda menulis fungsi atau metode yang menggunakannya, ketika Anda menghapusnya kode akan tetap berfungsi dengan baik, 100% tanpa itu. Misalnya:

Dengan params:

static public int addTwoEach(params int[] args)
{
    int sum = 0;
    foreach (var item in args)
        sum += item + 2;
    return sum;
}

Tanpa params:

static public int addTwoEach(int[] args)
{
    int sum = 0;
    foreach (var item in args)
       sum += item + 2;
    return sum;
}
MasterMastic
sumber
62
Kode metode itu sendiri masih akan berfungsi dengan baik ... kode panggilan mungkin tidak ...
Jon Skeet
7
kata kunci params berarti parameter OPTIONAL yang dapat diteruskan atau tidak ke Metode. Array tanpa kata kunci params berarti Anda HARUS meneruskan argumen array ke metode ini.
Ailayna Entarria
Bahasa Python mengimplementasikan konsep yang sama dengan manis dengan *parameter awalan asterisk ( ) seperti yang disebutkan di sini .
RBT

Jawaban:

485

Denganparams Anda dapat memanggil metode Anda seperti ini:

addTwoEach(1, 2, 3, 4, 5);

Tanpanya params, Anda tidak bisa.

Selain itu, Anda dapat memanggil metode dengan array sebagai parameter dalam kedua kasus :

addTwoEach(new int[] { 1, 2, 3, 4, 5 });

Artinya, paramsmemungkinkan Anda untuk menggunakan jalan pintas saat memanggil metode.

Tidak terkait, Anda dapat mempersingkat metode Anda secara drastis:

public static int addTwoEach(params int[] args)
{
    return args.Sum() + 2 * args.Length;
}
Konrad Rudolph
sumber
17
@ Ken: Anda mungkin perlu mengimpor System.Linqnamespace :)
Ranhiru Jude Cooray
49
Atau kembalikan args.Sum (i => i + 2);
bornfromanegg
2
Jumlah dengan delegasi, memang meningkatkan kompleksitas kode yang dikompilasi, yang berpotensi menjadi kurang berkinerja. Tidak benar-benar relevan dalam situasi khusus ini, karena tidak akan menghasilkan penutupan, tetapi perlu mengetahui apa yang sebenarnya dilakukan kompiler untuk membuat pilihan terbaik.
Allen Clark Copeland Jr
2
Anda juga dapat menggunakan return args.Select(x => x + 2).Sum();
bbvg
1
Ketika Anda menambahkan paramsAnda mengunci diri dari menambahkan argumen metode tambahan tanpa melanggar penelepon atau resolusi metode Anda.
Tuan Young
93

Menggunakan paramsmemungkinkan Anda untuk memanggil fungsi tanpa argumen. Tanpa params:

static public int addTwoEach(int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // throws an error

Bandingkan dengan params:

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // returns 0

Secara umum, Anda dapat menggunakan params ketika jumlah argumen dapat bervariasi dari 0 hingga tak terbatas, dan menggunakan array ketika jumlah argumen bervariasi dari 1 hingga tak terbatas.

Vasya
sumber
13
sebenarnya sebuah array bisa kosong. new int[0]. semoga ini membantu! :)
vidstige
22

Ini memungkinkan Anda untuk menambahkan sebanyak mungkin parameter tipe dasar dalam panggilan Anda.

addTwoEach(10, 2, 4, 6)

sedangkan dengan bentuk kedua Anda harus menggunakan array sebagai parameter

addTwoEach(new int[] {10,2,4,6})
okrumnow
sumber
17

Satu bahaya dengan paramsKata Kunci adalah, jika setelah Panggilan ke Kode telah dikodekan,

  1. seseorang secara tidak sengaja / sengaja menghapus satu / lebih Parameter yang diperlukan dari Metode Tanda Tangan, dan
  2. satu / lebih Parameter yang diperlukan segera sebelum paramsParameter sebelum perubahan Signature adalah Type-Kompatibel dengan paramsParameter,

Panggilan tersebut akan terus dikompilasi dengan satu / lebih Ekspresi yang sebelumnya dimaksudkan untuk Parameter yang diperlukan diperlakukan sebagai paramsParameter opsional . Saya baru saja menemukan kasus terburuk yang mungkin terjadi: paramsParameternya Type object[].

Ini patut diperhatikan karena pengembang terbiasa dengan kompilator yang menampar pergelangan tangan mereka dengan skenario yang jauh lebih umum di mana Parameter dihapus dari Metode dengan semua Parameter yang diperlukan (karena # Parameter yang diharapkan akan berubah).

Bagi saya, itu tidak sepadan dengan jalan pintas. (Type)[]tanpa paramsakan bekerja dengan 0 hingga tak terhingga # dari Parameter tanpa perlu Override. Kasus terburuk adalah Anda harus menambahkan , new (Type) [] {}ke Panggilan di mana itu tidak berlaku.

Btw, imho, praktik paling aman (dan paling mudah dibaca) adalah:

  1. lewat Parameter Bernama (yang sekarang dapat kita lakukan bahkan dalam C # ~ 2 dekade setelah kita dapat dalam VB; P) (karena:

    1.1. itu satu - satunya cara yang menjamin pencegahan nilai yang tidak disengaja diteruskan ke Parameter setelah urutan Parameter, Jenis Kompatibel dan / atau perubahan jumlah setelah Panggilan dikodekan,

    1.2. itu mengurangi peluang tersebut setelah perubahan makna Parameter, karena kemungkinan nama pengidentifikasi baru yang mencerminkan makna baru tepat di sebelah nilai yang diteruskan ke sana,

    1.3. itu menghindari keharusan untuk menghitung koma dan melompat-balik dari Call to Signature untuk melihat Ekspresi apa yang diberikan untuk Parameter apa, dan

    1.3.1. By the way, alasan ini saja harus banyak (dalam hal menghindari pelanggaran sering rawan dari Prinsip KERING hanya untuk membaca kode belum lagi juga memodifikasinya ), tetapi alasan ini bisa secara eksponensial lebih penting jika ada satu / lebih banyak Ekspresi yang Lulus yang mengandung koma, yaitu Array Multi-Dimensi atau Panggilan Fungsi Multi-Parameter. Dalam hal ini, Anda bahkan tidak bisa menggunakan (yang bahkan jika Anda bisa, masih akan menambahkan langkah ekstra per Parameter per Panggilan Metode) a Temukan Semua Kejadian dalam fitur Pilihan di editor Anda untuk mengotomatiskan penghitungan koma untuk Anda.

    1.4. jika Anda harus menggunakan Parameter Opsional ( paramsatau tidak), ini memungkinkan Anda untuk mencari Panggilan di mana Parameter Opsional tertentu dilewati (dan oleh karena itu, kemungkinan besar tidak atau setidaknya memiliki kemungkinan bukan Nilai Default),

(CATATAN: Alasan 1.2. Dan 1.3. Dapat memudahkan dan mengurangi kemungkinan kesalahan bahkan pada pengkodean Panggilan awal belum lagi ketika Panggilan harus dibaca dan / atau diubah.))

dan

  1. lakukan SATU - PARAMETER - PER - LINE untuk keterbacaan yang lebih baik (karena:

    2.1. itu kurang berantakan, dan

    2.2. ia menghindari keharusan menggulir ke kanan & belakang kiri (dan harus melakukannya PER - LINE, karena kebanyakan manusia tidak dapat membaca bagian kiri dari banyak baris, gulir ke kanan dan baca bagian kanan)).

    2.3. ini konsisten dengan "Praktik Terbaik" yang telah kami kembangkan untuk Pernyataan Tugas, karena setiap Parameter yang Lulus pada dasarnya adalah Pernyataan Tugas (memberikan Nilai atau Referensi ke Variabel Lokal). Sama seperti mereka yang mengikuti "Praktik Terbaik" terbaru dalam Gaya Pengkodean tidak akan bermimpi mengkode beberapa Pernyataan Tugas per baris, kita mungkin tidak seharusnya (dan tidak akan pernah "Praktik Terbaik" mengejar "jenius" saya; ) melakukannya saat Melewati Parameter.

CATATAN :

  1. Melewati Variabel yang namanya mencerminkan Parameter 'tidak membantu ketika:

    1.1. Anda melewati Konstanta Literal (yaitu 0/1 sederhana, salah / benar atau nol yang bahkan "'Praktik Terbaik'" mungkin tidak mengharuskan Anda menggunakan Konstan Bernama untuk dan tujuannya tidak dapat dengan mudah disimpulkan dari nama Metode ),

    1.2. Metode ini secara signifikan lebih rendah-tingkat / lebih umum daripada Penelepon sehingga Anda tidak ingin / dapat memberi nama Variabel Anda sama / mirip dengan Parameter (atau sebaliknya), atau

    1.3. Anda sedang memesan ulang / mengganti Parameter di Signature yang dapat mengakibatkan Panggilan sebelum masih Kompilasi karena Jenis terjadi masih kompatibel.

  2. Memiliki fitur auto-wrap seperti VS tidak hanya menghilangkan SATU (# 2.2) dari 8 alasan yang saya berikan di atas. Sebelum VS 2015, itu TIDAK otomatis inden (!?! Sungguh, MS?!?) Yang meningkatkan keparahan alasan # 2.1.

VS harus memiliki opsi yang menghasilkan snippet Pemanggilan Metode dengan Parameter Bernama (satu per baris tentu saja; P) dan opsi kompiler yang memerlukan Parameter Bernama (serupa dalam konsep dengan Option Explicit di VB yang, btw, persyaratannya sangat banyak sekali dipikirkan sama-sama keterlaluan tapi sekarang banyak dibutuhkan oleh "'Praktik Terbaik'"). Bahkan, "kembali ke sayahari ";), pada tahun 1991 hanya beberapa bulan dalam karier saya, bahkan sebelum saya menggunakan (atau bahkan telah melihat) bahasa dengan Parameter Bernama, saya memiliki anti-domba /" hanya karena Anda bisa, jangan berarti Anda harus " Saya tidak secara membuta "memotong ujung daging panggang" cukup masuk akal untuk mensimulasikannya (menggunakan komentar sebaris) tanpa melihat ada orang yang melakukannya. Tidak harus menggunakan Parameter Bernama (juga sintaks lainnya yang menyimpan "'berharga'" kode sumber penekanan tombol) adalah peninggalan era Kartu Punch ketika sebagian besar sintaks ini dimulai.Tidak ada alasan untuk itu dengan perangkat keras modern dan IDE dan perangkat lunak yang jauh lebih kompleks di mana keterbacaannya jauh, Banyak, JAUHlebih penting. "Kode dibaca lebih sering daripada yang tertulis". Selama Anda tidak menduplikasi kode yang tidak diperbarui secara otomatis, setiap keystroke yang disimpan kemungkinan akan lebih mahal secara eksponensial ketika seseorang (bahkan diri Anda) mencoba membacanya nanti.

Tom
sumber
2
Saya tidak mengerti. Mengapa Anda tidak bisa hanya menegakkan bahwa setidaknya ada satu? Bahkan tanpa params, tidak ada yang bisa menghentikan Anda untuk lulus nullatau new object[0]sebagai argumen.
Casey
Mungkin terlalu berbahaya untuk memiliki parameter yang diperlukan sebelum yang opsional (jika satu atau lebih dari yang diperlukan dihapus setelah panggilan dikodekan). Mungkin itulah sebabnya saya belum pernah melihat parameter yang diperlukan sebelum parameter opsional dalam kode sampel dalam dokumen apa pun tentang parameter opsional. Btw, imho, yang paling aman (dan praktik yang paling mudah dibaca) adalah melalui parameter bernama (yang sekarang bisa kita lakukan bahkan dalam C # ~ 2 dekade setelah kita bisa di VB). VS harus memiliki opsi yang menghasilkan potongan-potongan panggilan metode dengan parameter bernama (dan melakukannya 1 parameter per baris).
Tom
Saya tidak begitu yakin apa yang Anda maksud. Satu-satunya cara Anda dapat memiliki parameter yang diperlukan dan yang opsional adalah menentukan semua yang diperlukan terlebih dahulu.
Casey
1
Ex. Saya menyatakan myMethodsebagai void myMethod(int requiredInt, params int[] optionalInts). I / orang kode lain satu / lebih panggilan, yaitu myMethod(1), myMethod(1, 21), myMethod(1, 21, 22). Saya berubah myMethodmenjadi void myMethod(params int[] optionalInts). Semua panggilan itu masih akan dikompilasi tanpa kesalahan meskipun parameter pertama ("1") jelas tidak dimaksudkan untuk diteruskan sebagai elemen pertama dari optionalIntsParameter.
Tom
Oh Baiklah, dalam kasus khusus itu mungkin keliru. Saya tidak berpikir ada alasan untuk menghindarinya jika Anda memerlukan string dan int 0-to-many atau apa pun.
Casey
10

Tidak perlu membuat metode overload, cukup gunakan satu metode tunggal dengan params seperti yang ditunjukkan di bawah ini

// Call params method with one to four integer constant parameters.
//
int sum0 = addTwoEach();
int sum1 = addTwoEach(1);
int sum2 = addTwoEach(1, 2);
int sum3 = addTwoEach(3, 3, 3);
int sum4 = addTwoEach(2, 2, 2, 2);
listrikbah
sumber
Terima kasih atas masukan Anda, tetapi saya tidak berpikir kelebihan jenis ini akan menjadi solusi sama sekali karena dengan paramsatau tanpa kami hanya akan melewati jenis koleksi untuk menutupi jumlah koleksi.
MasterMastic
Anda benar pada batas tertentu tetapi apa yang membuatnya keren adalah kelebihan beban tanpa parameter input misalnya int sum1 = addTwoEach ();
electricalbah
5

params juga memungkinkan Anda memanggil metode dengan satu argumen.

private static int Foo(params int[] args) {
    int retVal = 0;
    Array.ForEach(args, (i) => retVal += i);
    return retVal;
}

yaitu Foo(1);bukannya Foo(new int[] { 1 });. Dapat berguna untuk steno dalam skenario di mana Anda mungkin harus memberikan nilai tunggal daripada seluruh array. Ini masih ditangani dengan cara yang sama dalam metode ini, tetapi memberikan beberapa permen untuk memanggil dengan cara ini.

David Anderson
sumber
5

Menambahkan kata kunci params itu sendiri menunjukkan bahwa Anda dapat melewati beberapa parameter saat memanggil metode yang tidak mungkin dilakukan tanpa menggunakannya. Untuk lebih spesifik:

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

Ketika Anda akan memanggil metode di atas, Anda dapat memanggilnya dengan salah satu cara berikut:

  1. addTwoEach()
  2. addTwoEach(1)
  3. addTwoEach(new int[]{ 1, 2, 3, 4 })

Tetapi ketika Anda akan menghapus kata kunci params hanya cara ketiga dari cara yang diberikan di atas akan bekerja dengan baik. Untuk kasus 1 dan 2 Anda akan mendapatkan kesalahan.

Ashwini
sumber
0

Satu hal lagi yang perlu disorot. Lebih baik digunakan paramskarena lebih baik untuk kinerja. Saat Anda memanggil metode dengan paramsargumen dan tidak memberikan apa pun:

public void ExampleMethod(params string[] args)
{
// do some stuff
}

panggilan:

ExampleMethod();

Kemudian versi baru dari .Net Framework melakukan ini (dari .Net Framework 4.6):

ExampleMethod(Array.Empty<string>());

Array.EmptyObjek ini dapat digunakan kembali oleh kerangka kerja nanti, sehingga tidak perlu melakukan alokasi berlebihan. Alokasi ini akan terjadi ketika Anda memanggil metode ini seperti ini:

 ExampleMethod(new string[] {});
Beniamin Makal
sumber
0

Mungkin terdengar bodoh, Tapi Params tidak mengizinkan array multidimensi. Sedangkan Anda bisa meneruskan array multidimensi ke suatu fungsi.

Manoj Kumar
sumber
0

Contoh lain

public IEnumerable<string> Tokenize(params string[] words)
{
  ...
}

var items = Tokenize(product.Name, product.FullName, product.Xyz)
skjagini
sumber