Tek bir nesne [] bir params nesnesine [] nasıl geçirilir


124

Params nesnesini [] alan bir yöntemim var, örneğin:

void Foo(params object[] items)
{
    Console.WriteLine(items[0]);
}

Bu yönteme iki nesne dizisi geçirdiğimde iyi çalışıyor:

Foo(new object[]{ (object)"1", (object)"2" }, new object[]{ (object)"3", (object)"4" } );
// Output: System.Object[]

Ama tek bir nesneyi [] geçtiğimde, nesnemi [] ilk parametre olarak almaz, bunun yerine tüm unsurlarını tek tek geçmek istediğim gibi alır:

Foo(new object[]{ (object)"1", (object)"2" });
// Output: 1, expected: System.Object[]

Bir params dizisine ilk argüman olarak tek bir nesneyi [] nasıl iletirim?

Yanıtlar:


99

Basit bir typecast, derleyicinin bu durumda ne demek istediğinizi anlamasını sağlar.

Foo((object)new object[]{ (object)"1", (object)"2" }));

Bir dizi nesnenin bir alt türü olduğu için, bunların hepsi işe yarar. Yine de biraz garip bir çözüm, aynı fikirdeyim.


2
Diğer dillerde alıştığımız şey göz önüne alındığında, parametrelerin çalışma şekli gereksiz ve yetersiz c # tasarımı gibi görünüyor. Parametreler yalnızca bir formu kabul edecek şekilde yapılabilirdi ve yalnızca bu durumda değil, tüm dile fayda sağlayacak yayılma benzeri bir özellik eklenebilirdi. örneğin, tüm param çağrılarını Foo (obj [0], obj [1]) olmaya zorlayabilir ve ardından Foo (... obj) 'e izin veren ayrı bir spread operatörüne sahip olabiliriz.
whitneyland

1
anders hejlsberg'e büyük saygı duyduğumu açıkça belirtmediğimi fark etti, o dünyanın en iyi dil tasarımcılarından biri. ancak yeterince ileri görüş verildiğinde, herhangi birinin çalışmasında, dolayısıyla teknolojide iyileştirmeler düşünebiliriz.
whitneyland

74

paramsParametre değiştirici arayanlar için bir yönteme birden fazla argüman geçmesi için bir kısayol sözdizimi sağlar. paramsParametreli bir yöntemi çağırmanın iki yolu vardır :

1) Parametre türünde bir dizi ile çağrı yapmak, bu durumda paramsanahtar kelimenin hiçbir etkisi olmaz ve dizi doğrudan yönteme iletilir:

object[] array = new[] { "1", "2" };

// Foo receives the 'array' argument directly.
Foo( array );

2) Veya, genişletilmiş bir argüman listesiyle arama, bu durumda derleyici argüman listesini otomatik olarak geçici bir diziye sarar ve bunu yönteme iletir:

// Foo receives a temporary array containing the list of arguments.
Foo( "1", "2" );

// This is equivalent to:
object[] temp = new[] { "1", "2" );
Foo( temp );


Bir nesne dizisini " params object[]" parametresine sahip bir yönteme geçirmek için şunlardan birini yapabilirsiniz:

1) Manuel olarak bir sarmalayıcı dizisi oluşturun ve bunu lassevk'te belirtildiği gibi doğrudan yönteme iletin :

Foo( new object[] { array } );  // Equivalent to calling convention 1.

2) Veya, argümanı Adamobject tarafından belirtildiği gibi atayın , bu durumda derleyici sizin için sarmalayıcı diziyi oluşturacaktır:

Foo( (object)array );  // Equivalent to calling convention 2.


Ancak, yöntemin amacı birden çok nesne dizisini işlemekse, bunu açık bir " params object[][]" parametresiyle bildirmek daha kolay olabilir . Bu, birden çok diziyi bağımsız değişken olarak geçirmenize izin verir:

void Foo( params object[][] arrays ) {
  foreach( object[] array in arrays ) {
    // process array
  }
}

...
Foo( new[] { "1", "2" }, new[] { "3", "4" } );

// Equivalent to:
object[][] arrays = new[] {
  new[] { "1", "2" },
  new[] { "3", "4" }
};
Foo( arrays );

Düzenleme: Raymond Chen, bu davranışı ve yeni bir gönderide C # spesifikasyonuyla nasıl ilişkili olduğunu açıklıyor .


8

Bu, LINQ içeren tek satırlık bir çözümdür.

var elements = new String[] { "1", "2", "3" };
Foo(elements.Cast<object>().ToArray())

3

Bunu başka bir nesne [] dizisine sarmalamanız gerekir, örneğin:

Foo(new Object[] { new object[]{ (object)"1", (object)"2" }});

2

Bu sorunu çözmenin başka bir yolu (çok iyi bir uygulama değil ama güzel görünüyor):

static class Helper
{
    public static object AsSingleParam(this object[] arg)
    {
       return (object)arg;
    }
}

Kullanımı:

f(new object[] { 1, 2, 3 }.AsSingleParam());

1

Bir seçenek, onu başka bir diziye sarabilmenizdir:

Foo(new object[]{ new object[]{ (object)"1", (object)"2" } });

Biraz çirkin, ancak her öğe bir dizi olduğundan, sorunu ortadan kaldırmak için onu çeviremezsiniz ... mesela Foo (params nesne öğeleri) gibi, o zaman şunları yapabilirsiniz:

Foo((object) new object[]{ (object)"1", (object)"2" });

Alternatif olarak, yalnızca tek bir dizi alan başka bir aşırı yüklenmiş Foo örneğini tanımlamayı deneyebilirsiniz:

void Foo(object[] item)
{
    // Somehow don't duplicate Foo(object[]) and
    // Foo(params object[]) without making an infinite
    // recursive call... maybe something like
    // FooImpl(params object[] items) and then this
    // could invoke it via:
    // FooImpl(new object[] { item });
}

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.