Neden params anahtar sözcüğünü kullanmalıyım?


336

Bunun temel bir soru olduğunu biliyorum, ama bir cevap bulamadım.

Neden kullanmalıyım? eğer bir fonksiyon veya onu kullanan bir yöntem yazarsanız, onu kaldırdığınızda kod hala mükemmel şekilde çalışır,% 100 onsuz olduğu gibi. Örneğin:

Params ile:

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

Params olmadan:

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

62
Yöntemin kendisi hala mükemmel bir şekilde çalışacaktır ... çağıran kod iyi olmayabilir ...
Jon Skeet 28:30

7
params anahtar sözcüğü, Yönteme iletilebilen veya iletilemeyen İSTEĞE BAĞLI parametreler anlamına gelir. Out params anahtar kelimesi olan bir dizi, yönteme dizi bağımsız değişkenini iletmeniz gerektiği anlamına gelir.
Ailayna Entarria

Python dili, aynı kavramı burada* belirtildiği gibi bir yıldız ( ) önek parametresi ile çok tatlı bir şekilde uygular .
RBT

Yanıtlar:


485

İleparams yönteminizi şöyle çağırabilirsiniz:

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

Olmadan paramsyapamazsın.

Ayrıca, her iki durumda da yöntemi bir dizi ile parametre olarak çağırabilirsiniz :

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

Yani, paramsyöntemi çağırırken bir kısayol kullanmanıza izin verir.

İlgisiz, yönteminizi büyük ölçüde kısaltabilirsiniz:

public static int addTwoEach(params int[] args)
{
    return args.Sum() + 2 * args.Length;
}

17
@Ken: Ad System.Linqalanını içe aktarmanız gerekebilir :)
Ranhiru Jude Cooray

49
Veya args döndür. Sum (i => i + 2);
bornfromanegg

2
Yine de bir delege ile toplam, derlenmiş kodun karmaşıklığını artırır, bu da potansiyel olarak daha az performans gösterebilir. Herhangi bir kapanmaya yol açmayacağından, bu özel durumda gerçekten alakalı değil, ancak derleyicinin en iyi seçimi yapmak için gerçekte ne yaptığını bilmeye değer.
Allen Clark Copeland Jr

2
Ayrıca kullanabilirsiniz return args.Select(x => x + 2).Sum();
bbvg

1
Eğer eklediğinizde paramssize kilitlemek arayanlar veya yöntem çözünürlüğü bozmadan ek yöntem argümanlar ekleyerek kendinizi.
Bay Young

93

Kullanmak paramsişlevi bağımsız değişken olmadan çağırmanızı sağlar. Olmadan params:

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

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

    return sum;
}

addtwoEach(); // throws an error

Şununla karşılaştır params:

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

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

    return sum;
}

addtwoEach(); // returns 0

Genel olarak, bağımsız değişken sayısı 0'dan sonsuza değiştiğinde parametreler kullanabilir ve bağımsız değişken sayısı 1'den sonsuza değiştiğinde bir dizi kullanabilirsiniz.


13
aslında bir dizi boş olabilir. new int[0]. Bu yardımcı olur umarım! :)
vidstige

22

Çağrınıza istediğiniz kadar temel tip parametresi eklemenizi sağlar.

addTwoEach(10, 2, 4, 6)

ikinci formda ise parametre olarak bir dizi kullanmanız gerekir

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

17

Tek tehlike paramsKelime, eğer bir sonraki Yöntem yapılan aramalar, kodlanmış olan

  1. birisi yanlışlıkla / kasıtlı olarak bir / daha fazla gerekli Parametreyi Yöntem İmzasından kaldırır ve
  2. bir / daha fazla Gerekliparams İmza değişikliğinden önce Parametre'den hemen önceki Parametreler Parametre ile Tür Uyumlu params,

bu Çağrılar daha önce isteğe bağlı Parametre olarak kabul edilen gerekli Parametreler için tasarlanan bir / daha fazla İfade ile derlemeye devam edecektir params. Sadece bunun en kötü durumuyla karşılaştım: paramsParametre Type idi object[].

Bu dikkat çekicidir, çünkü geliştiriciler bileklerini tokatlamak için derleyicilere, gerekli tüm Parametrelerle Parametrelerin Bir Yöntemden kaldırıldığı (çünkü beklenen Parametrelerin # değişeceği) senaryo ile kullanılırlar .

Benim için kısayola değmez. (Type)[]olmadan params, Geçersiz Kılmalara gerek kalmadan 0 ila sonsuz # Parametreyle çalışır. En kötü durum, , new (Type) [] {}geçerli olmadığı Çağrılara a eklemeniz gerekecek .

Btw, imho, en güvenli (ve en okunabilir uygulama):

  1. Adlandırılmış Parametreler üzerinden geçin (şimdi VB; P'den sonra C # ~ 2 yıl içinde bile yapabiliriz ) (çünkü:

    1.1. öyle sadece bu şekilde garanti istenmeyen değerlerin önleme Parametre düzeni, Uyumlu-Type sonra Parametreler geçirilen ve / veya Çağrılar kodlanmış sonra değişiklik saymak,

    1.2. o azaltan yeni bir anlam yansıtan olasılıkla yeni tanımlayıcı adı hemen yanındaki değeri kendisine geçirilen etmektir, çünkü bir parametre anlamı değişikliğinden sonra bu şansı

    1.3. Parametre için hangi İfadenin geçildiğini görmek için virgül saymak ve Çağrıdan İmzaya atlamak zorunda kalmaz ve

    1.3.1. Bu arada, bu nedenle tek başına olmalıdır bol (sadece DRY İlke sık hataya yatkın ihlallerinden kaçınmaya açısından okunan kodu da saymıyorum değiştirmek o), ancak bu nedenle olabilir katlanarak tane varsa daha önemli / daha fazla Kendileri virgül içeren İfadeler Geçirilir, yani Çok Boyutlu Dizi Referansları veya Çok Parametreli İşlev Çağrıları. Bu durumda, hatta (eğer hala fazladan bir adımdan olacağını olabilir bile hangi kullanamadı başına Parametre başına sizin için virgül sayım otomatik hale getirmek için düzenleyici bir bir Seçim özelliği bütün değişikliklerini Bul Yöntem Çağrısı).

    1.4. İsteğe Bağlı Parametreleri kullanmanız ( paramsveya kullanmamanız) gerekiyorsa, belirli bir İsteğe Bağlı Parametrenin Geçirildiği Çağrıları aramanıza olanak tanır (ve bu nedenle, büyük olasılıkla Varsayılan Değer değil veya en azından Varsayılan Değer olma olasılığı vardır),

(NOT: 1.2 ve 1.3 nedenleri, ilk Çağrıları kodlarken bile Çağrıların ne zaman okunması ve / veya değiştirilmesi gerektiğinden bahsetmemek için hata olasılığını azaltabilir ve azaltabilir.))

ve

  1. daha iyi okunabilirlik için ONE - PARAMETER - PER - LINE yapın (çünkü:

    2.1. daha az dağınık ve

    2.2. sağa ve sola kaydırmaktan kaçınır (ve PER - LINE yapmak zorunda kalmaz, çünkü çoğu ölümcül birden çok satırın sol kısmını okuyamaz, sağa kaydırır ve sağ kısmı okuyamaz)).

    2.3. Atama İfadeleri için zaten geliştirdiğimiz "En İyi Uygulama" ile tutarlıdır, çünkü Geçirilen her Parametre özünde bir Atama İfadesidir (bir Yerel Değişkene Değer veya Referans atama). Kodlama Stili'ndeki en son "En İyi Uygulama" yı takip edenler gibi , satır başına birden fazla Atama İfadesi kodlamayı hayal etmeyecek gibi, muhtemelen "En İyi Uygulama" benim dehamı yakalamamalıdır ( P) ) parametrelerini iletirken bunu yapın.

NOTLAR :

  1. Aşağıdaki durumlarda adları Parametreleri yansıtan Değişkenleri iletmek yardımcı olmaz:

    1.1. Değişmez Sabitleri (yani, "En İyi Uygulamalar" bile bile Adlandırılmış Sabit kullanmanızı gerektirmeyebilecek ve amaçları Yöntem adından kolayca çıkarılamayacak basit bir 0/1, yanlış / doğru veya boş ),

    1.2. Yöntem, Değişkenlerinizi Parametrelerle aynı / benzer (veya tersi) olarak adlandırmak istemeyeceğiniz / bulamayacağınız Arayan'dan önemli ölçüde daha düşük düzey / daha geneldir veya

    1.3. Eğer sizsiniz, yeniden sıralama / Tipleri çünkü hala Derleme önceki Aramalar neden olabilir İmza Parametreleri değiştirirken gerçekleşmesi hala uyumlu olacak şekilde.

  2. VS gibi bir otomatik sarma özelliğine sahip olmak, yukarıda verdiğim 8 nedenden sadece BİRİNİ (# 2.2) ortadan kaldırır. VS 2015 kadar geç bir süre önce, # 2.1 nedeninin şiddetini artıran otomatik girintiyi (!?! Gerçekten MS?!?)

VS, Adlandırılmış Parametrelerle (elbette her satırda bir; P) Yöntem Çağrısı snippet'leri üreten bir seçeneğe ve Adlandırılmış Parametreler gerektiren bir derleyici seçeneğine (btw, gereksiniminin bir zamanlar düşünüldüğü VB'de Seçenek Seçeneğine benzer) sahip olmalıdır. eşit derecede çirkin ama artık "En İyi Uygulamalar" tarafından zorunlu olarak isteniyor ). İçinde Aslında, "arka benimday ";), 1991'de sadece aylar içinde, Named Parameters ile bir dil kullanmadan (veya görmeden) bile, anti-sheeple'ım vardı /" sadece çünkü yapabilirsin, yapman gerektiği anlamına gelmez " / körü körüne "kızartmanın uçlarını kesmeyin" kimsenin bunu görmeden onu simüle edecek şekilde (satır içi yorumlar kullanarak). kaynak kodu tuş vuruşları) bu sözdizimlerinin çoğu başladığında Punch Card döneminin bir kalıntısıdır.Onun modern donanım ve IDE'leri ve okunabilirliğin çok, çok, çok daha fazla olduğu çok daha karmaşık bir yazılımla bunun mazereti yoktur.daha önemli. "Kod yazıldığından çok daha sık okunur". Otomatik olarak güncellenmeyen kodu çoğaltmadığınız sürece, kaydedilen her tuş vuruşu biri (hatta kendiniz) daha sonra okumaya çalıştığında katlanarak daha pahalıya mal olur.


2
Anlamıyorum. Neden en az bir tane olduğunu zorlayamıyorsun? Paramsuz bile sizi geçmenizi nullveya new object[0]argüman olarak durduracak hiçbir şey yoktur .
Casey

Muhtemelen isteğe bağlı parametreden önce gerekli parametrelere sahip olmak çok tehlikelidir (bu kodlardan bir veya daha fazlasının çağrılar kodlandıktan sonra kaldırılması durumunda). Bu yüzden isteğe bağlı parametreler üzerinde herhangi bir dokümanda örnek kodda isteğe bağlı parametre önce gerekli parametreleri hiç görmedim olabilir. Btw, imho, en güvenli (ve en okunabilir uygulama) adlandırılmış parametrelerden geçmektir (şimdi VB'de C # ~ 2 yıl sonra bile yapabiliriz ). VS, adlandırılmış parametrelerle yöntem çağırma snippet'leri üreten bir seçeneğe sahip olmalıdır (ve her satıra 1 parametre).
Tom

Ne demek istediğinden emin değilim. Gerekli parametrelere ve isteğe bağlı parametrelere sahip olmanın tek yolu önce gerekli olanları belirtmektir.
Casey

1
Ör. Ben beyan myMethodolarak void myMethod(int requiredInt, params int[] optionalInts). I / başkasının kodları tek / daha fazla çağrı, yani myMethod(1), myMethod(1, 21), myMethod(1, 21, 22). Değişmek myMethodolmak void myMethod(params int[] optionalInts). 1. parametrelerinin ("1" ler) optionalIntsParametrenin 1. öğesi olarak açıkça geçmesi amaçlanmamış olsa da, tüm bu çağrılar hatasız derlenecektir .
Tom

Ah. Tamam, bu durumda kötü tavsiye edilebilir. Ben bir dize ve 0-çok ints ya da her neyse ihtiyacınız önlemek için herhangi bir neden olduğunu sanmıyorum.
Casey

10

Aşırı yük yöntemleri oluşturmanıza gerek yok, sadece aşağıda gösterildiği gibi parametrelerle tek bir yöntem kullanın

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

Girişiniz için teşekkürler, ancak bu tür aşırı yüklerin, paramsherhangi bir koleksiyon sayısını kapsamak için sadece bir koleksiyon türü geçeceğimiz veya onsuz bir çözüm olacağını düşünmüyorum .
MasterMastic

Bir dereceye kadar haklısınız, ancak onu serinleten şey, giriş parametresi olmayan bir aşırı yüktür örn. İnt sum1 = addTwoEach ();
electricbah

5

params yöntemi tek bir argümanla çağırmanıza da olanak tanır.

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

yani Foo(1);yerine Foo(new int[] { 1 });. Tüm dizi yerine tek bir değer vermeniz gerekebilecek senaryolarda steno için yararlı olabilir. Yine de yöntemde aynı şekilde ele alınır, ancak bu şekilde çağırmak için biraz şeker verir.


5

Params anahtar sözcüğünün eklenmesi, bu yöntemi çağırmadan kullanmadan mümkün olmayan birden fazla parametre geçirebileceğinizi gösterir. Daha spesifik olmak gerekirse:

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

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

    return sum;
}

Yukarıdaki yöntemi arayacağınız zaman, aşağıdaki yöntemlerden birini kullanarak arayabilirsiniz:

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

Ancak params anahtar sözcüğünü kaldırdığınızda, yukarıda belirtilen yolların yalnızca üçüncü yolu iyi çalışır. 1. ve 2. vaka için bir hata alırsınız.


0

Daha önemli bir şeyin vurgulanması gerekir. Kullanmak daha iyidir paramsçünkü performans için daha iyidir. Bağımsız paramsdeğişkenli bir yöntemi çağırıp ona bir şey ilettiğinizde:

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

aramak:

ExampleMethod();

Sonra .Net Framework'ün yeni sürümleri bunu (.Net Framework 4.6'dan) yapar:

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

Bu Array.Emptynesne daha sonra çerçeve ile yeniden kullanılabilir, bu nedenle fazladan ayırma yapmaya gerek yoktur. Bu ayırma, bu yöntemi şöyle çağırdığınızda gerçekleşir:

 ExampleMethod(new string[] {});

0

Kulağa aptal gelebilir, ancak Params çok boyutlu diziye izin vermez. Oysa bir işleve çok boyutlu bir dizi geçirebilirsiniz.


0

Başka bir örnek

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

var items = Tokenize(product.Name, product.FullName, product.Xyz)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.