Sınırsız params ile c # yöntemi veya bir dizi veya liste yöntemi?


21

Son zamanlarda sınırsız parametrelerle bazı yöntem oluşturabileceğinizi öğrendim, örneğin:

SomeMethod(params int[] numbers);

ama sorum şu: bunun arasındaki fark nedir ve sadece bir liste veya dizi alan bir yöntem oluşturmak mı?

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

belki de performans üzerinde bir etkisi vardır? Sınırsız parametreli olanı ne şekilde tercih edeceğinizi tam olarak anlamıyorum veya görmüyorum.

Google'da hızlı bir arama yardımcı olmadı, umarım bana yardımcı olabilirsiniz.



Aşağıdaki yanıtıma ek olarak , argüman türünün bir dizi olmasınıparams da gerektirir . Dizi dışında bir koleksiyon tüketmeniz gerekiyorsa, bunun paramsyerine bağımsız değişken sağlamak daha mantıklı olabilir .
digitlworld

1
@digitlworld: Bu konu ilginizi çekiyorsa , tartışma için github.com/dotnet/csharplang/issues/179 adresine bakın .
Eric Lippert

İmzasına ve / veya uygulanmasına bakın Console.Write.
3Dave

Yanıtlar:


27

Bu ve sadece bir liste veya dizi alan bir yöntem oluşturmak arasındaki fark nedir?

Arasındaki fark

void M(params int[] x)

ve

void N(int[] x)

M şu şekilde adlandırılabilir:

M(1, 2, 3)

ya da bunun gibi:

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

ancak N yalnızca ikinci şekilde çağrılabilir , ilk şekilde çağrılamaz.

belki de performans üzerinde bir etkisi vardır?

Performansın etkisi, ister Mbirinci şekilde ister ikinci şekilde, ister her iki şekilde de bir dizi oluşturduğunuzda olsun. Dizi oluşturmak hem performans hem de bellek gerektirdiğinden performans etkisi vardır. Performans etkilerinin performans hedeflerine göre ölçülmesi gerektiğini unutmayın; ekstra bir dizi yaratmanın maliyetinin, piyasadaki başarı ve başarısızlık arasındaki fark olan kapı faktörü olması pek olası değildir.

Sınırsız parametreli olanı ne şekilde tercih edeceğinizi tam olarak anlamıyorum veya görmüyorum.

Yöntemi çağıran kodun yazarı için tamamen ve tamamen bir kolaylıktır; o basitçe daha kısa ve daha kolay yazma için

M(1, 2, 3);

yazmak yerine

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

Arayanın tarafında birkaç tuşa dokunur. Hepsi bu.

Sormadığınız, ancak belki de cevabını bilmek istediğiniz birkaç soru:

Bu özelliğin adı nedir?

Bağımsız değişken sayıda arayan tarafında geçirilen izin yöntemler denir değişkin . Param yöntemleri C # 'ın varyasyon yöntemlerini nasıl uyguladığıdır.

Aşırı yük çözünürlüğü değişken bir yöntemle nasıl çalışır?

Aşırı yük çözümleme sorunu ile karşılaşıldığında, C # hem "normal" hem de "genişletilmiş" formları dikkate alacaktır ve her ikisi de uygulanabilirse "normal" form her zaman kazanır. Örneğin, şunu düşünün:

void P(params object[] x){}

ve bir telefonumuz var

P(null);

Uygulanabilir iki olasılık vardır. "Normal" formda, Pdizi için boş bir referans çağırıp iletiriz. "Genişletilmiş" formda çağırırız P(new object[] { null }). Bu durumda, normal form kazanır. Bir çağrımız P(null, null)varsa, normal form uygulanamaz ve genişletilmiş form varsayılan olarak kazanır.

Zorluk : Varsayalım var s = new[] { "hello" };ve bir çağrı var P(s);. Çağrı sitesinde neler olduğunu ve nedenini açıklayın. Şaşırmış olabilirsiniz!

Mücadelesi : ikimiz de olduğunu varsayalım void P(object x){}ve void P(params object[] x){}. Ne P(null)işe yarar ve neden?

Mücadelesi : ikimiz de olduğunu varsayalım void M(string x){}ve void M(params string[] x){}. Ne M(null)işe yarar ve neden? Bu bir önceki durumdan nasıl farklı?


Ch2: P(null)vs. P((object)null)vs. P((object[])null)- Bu farkın açıklamasını nerede bulabilirim? Nesne ( ) yerine diziye dönüşen bazı özel türlere sahip gibi geliyor , ancak dizeye veya belirsiz dizgiye diziyi dönüştürmeyi buluyor ( ) ... çok garip hissettiriyor, her iki durumda da belirsiz olmasını veya seçim yapmasını bekler tek argümanlı sürümü (ki öyle değil). Ama sanırım C ++ şablonlarında evrensel referans ( ) gibi bir şekilde genel olmak ve daha iyi eşleştirmek (Ch2'de değil, Ch3'te değil). nullP(null)M(null)params&&
firda

@firda: Açıklamayı C # belirtiminde bulabilirsiniz. Tuhaflığın nedeni: null, nesneye, dizgiye, nesneye [] ve dizgiye [] dönüştürülebilir. O zaman aşırı yük çözünürlüğüne yöneltilen soru şudur: hangi dönüşüm en iyisidir ? Bu durumda kontrol kuralı spesifiktir, genelden daha iyidir . Hangi türün daha spesifik olduğunu nasıl anlarız? Kural şudur: tüm zürafalar hayvanlardır, ancak tüm hayvanlar zürafa değildir, bu nedenle zürafa hayvandan daha belirgindir. Tüm object[]vardır object, ama hepsi değil objectvardır object[]bu nedenle object[]daha özeldir.
Eric Lippert

@firda: Artık dizelerin neden belirsiz olduğunu biliyorsunuz. O "bütün bu doğru değil string[]vardır string." Aslında HAYIR string[]vardır stringve NO stringvardır string[]bu yüzden, stringdaha spesifik veya daha genel değildir string[]ve seçim için sorulduğunda biz bir belirsizlik hatası alıyorum.
Eric Lippert

Tüm object[]vardır object... object[]daha özeldir bu yüzden P(null)ne eksik olduğunu olduğunu, daha spesifik dizi thx için de geçerli. Burada bazı kurallar buldum
firda

5

Biraz prototip yaptım. Cevap params, bir diziye geçmek için basitçe sözdizimsel şeker olduğu anlaşılıyor . Bu gerçekten bir sürpriz değil. Tek farkın "params" anahtar kelimesi olduğu, aynı yöntemin iki sürümünü oluşturdum. Her ikisi için üretilen IL, aynıydı, ancak a System.ParamArrayAttribute, paramssürüme uygulandı .

Ayrıca, çağrı yerinde üretilen IL de elle bir beyan new int[]ile yöntemi çağırmak ve sadece paramsargümanlar kullanarak yöntemi çağırmak arasında aynı idi .

Yani, cevap "kolaylık" gibi görünüyor. Performansta herhangi bir fark yok gibi görünüyor. Bunun paramsyerine dizi içeren bir işlevi de çağırabilirsiniz , bu da çok şaşırtıcı değildir. Metodunuzun tüketicisinin, onu someMethod(1, 2, 3)her zaman önce bir koleksiyon (örn. ) Oluşturmaktan daha fazla sayıda parametre (örneğin ) ile çağırmasının daha kolay olup olmadığı anlaşılır someMethod(new List<int>() { 1, 2, 3 } ).


4

Sınırsız parametrelerin özelliği, birçok senaryoda aşağıdaki avantajları sunar:

  1. Gevşek bağlantı
  2. Gelişmiş yeniden kullanılabilirlik
  3. Uygulamanın daha iyi genel performansı

İşte sınırsız parametre seçeneğinin mükemmel bir seçim olduğu bir örnek

E-posta göndermek için bir uygulamanın oluşturulması gerektiğini düşünün.

E-postayı gönderen işlev, 'Kime', 'CC' ve 'BCC' alanları için tek veya birden çok değeri işleyebilmelidir.

Parametre türleri tüm alanlar için diziler veya listeler olarak sabitlenirse (Kime, CC, BCC), çağrı işlevi, e-posta gönderen işlevini çağırmak için 3 dizi veya liste tanımlamanın tüm karmaşıklığıyla uğraşmak zorunda kalacaktır. .

Arayan yalnızca bir adrese e-posta göndermek istese bile, e-posta gönderen işlevi arayanı parametre olarak 3 farklı dizi tanımlamaya ve göndermeye zorlar.

E-posta gönderen işlevi sınırsız params yaklaşımını kullanıyorsa, arayan işlevinin tüm karmaşıklığı ele alması gerekmez.

Sınırsız parametre yaklaşımı, gereksiz yerlerde dizilerin veya listelerin oluşturulmasını önleyerek uygulamanın daha iyi çalışma süresi performansına katkıda bulunur.


2

Bir itibaren dışı performans , stil perspektiften, paramsanahtar kelime size parametrelerin isteğe bağlı listesini göndermek istediğinizde olması gerçekten güzel.

Şahsen, paramsbenim kod gibi bir şey olduğunda kullanmak istiyorum

SomeMethod('Option1', 'Option17');

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

Bu konuda güzel kısmı, bu yöntemi her yerde bir dizi veya liste oluşturmak zorunda kalmadan kullanabilmenizdir.

Kullanırdım arrayveya listbildiğim zaman bu işlevi her zaman bir araya getirecek bir veri kümesi geçireceğim.

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

paramsEklediği esneklikte fayda görüyorum . Kodunuz üzerinde nispeten küçük bir etki olabilir, ancak yine de olması güzel bir araçtır.


1

Çağrı kuralı farklıdır. Örneğin ...

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

İlk durumda, yönteme ayrı parametreler kadar çok ints iletebilirsiniz. İkincisinde, bir liste başlatmanız ve geçmeniz gerekir.

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.