Cara melewatkan satu objek [] ke objek params []

124

Saya memiliki metode yang mengambil objek params [] seperti:

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

Ketika saya melewatkan dua array objek ke metode ini, itu berfungsi dengan baik:

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

Tapi ketika saya melewatkan satu objek [], itu tidak mengambil objek saya [] sebagai parameter pertama, melainkan mengambil semua elemennya seperti saya ingin meneruskannya satu per satu:

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

Bagaimana cara mengirimkan satu objek [] sebagai argumen pertama ke array params?

Serhat Ozgel
sumber

Jawaban:

99

Typecast sederhana akan memastikan kompiler tahu apa yang Anda maksud dalam kasus ini.

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

Karena array adalah subtipe objek, ini semua berhasil. Sedikit solusi yang aneh, saya setuju.

Adam Wright
sumber
2
cara kerja params tampaknya tidak diperlukan, dan desain c # yang kurang optimal, mengingat apa yang sudah biasa kita gunakan dalam bahasa lain. params dapat dibuat hanya untuk menerima satu bentuk, dan fitur seperti penyebaran dapat ditambahkan yang akan menguntungkan seluruh bahasa, tidak hanya kasus ini. misalnya, kita dapat memaksa semua panggilan param menjadi Foo (obj [0], obj [1]), dan kemudian memiliki operator penyebaran terpisah yang mengizinkan Foo (... obj).
whitneyland
1
menyadari saya tidak menjelaskan bahwa saya sangat menghormati anders hejlsberg, dia salah satu desainer bahasa terbaik di dunia. tetapi kami dapat memikirkan tentang peningkatan pada pekerjaan siapa pun dengan melihat ke belakang, karena itu teknologi.
whitneyland
74

The paramsparameter pengubah memberikan penelepon sintaks pintas untuk melewati beberapa argumen untuk sebuah metode. Ada dua cara untuk memanggil metode dengan paramsparameter:

1) Memanggil dengan array tipe parameter, dalam hal ini paramskata kunci tidak berpengaruh dan array tersebut diteruskan langsung ke metode:

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

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

2) Atau, memanggil dengan daftar argumen yang diperpanjang, dalam hal ini kompilator akan secara otomatis membungkus daftar argumen dalam larik sementara dan meneruskannya ke metode:

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

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


Untuk meneruskan larik objek ke metode dengan params object[]parameter " ", Anda dapat:

1) Buat array pembungkus secara manual dan teruskan langsung ke metode, seperti yang disebutkan oleh lassevk :

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

2) Atau, berikan argumen ke object, seperti yang disebutkan oleh Adam , dalam hal ini kompilator akan membuat array pembungkus untuk Anda:

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


Akan tetapi, jika tujuan metode ini adalah untuk memproses beberapa larik objek, mungkin lebih mudah untuk mendeklarasikannya dengan params object[][]parameter " " eksplisit . Ini akan memungkinkan Anda untuk melewatkan beberapa array sebagai argumen:

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

Sunting: Raymond Chen menjelaskan perilaku ini dan bagaimana kaitannya dengan spesifikasi C # di posting baru .

Kaisar XLII
sumber
8

Ini adalah solusi satu baris yang melibatkan LINQ.

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

Anda perlu merangkumnya ke dalam larik [] objek lain, seperti ini:

Foo(new Object[] { new object[]{ (object)"1", (object)"2" }});
Lasse V. Karlsen
sumber
2

Cara lain untuk mengatasi masalah ini (ini bukan praktik yang baik tetapi terlihat cantik):

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

Pemakaian:

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

Salah satu opsinya adalah Anda dapat menggabungkannya ke dalam array lain:

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

Agak jelek, tetapi karena setiap item adalah sebuah array, Anda tidak bisa membuangnya begitu saja untuk menghilangkan masalah ... seperti jika itu adalah Foo (item objek params), maka Anda dapat melakukan:

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

Sebagai alternatif, Anda dapat mencoba menentukan instance Foo lain yang kelebihan beban yang hanya membutuhkan satu larik:

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 });
}
Mike Stone
sumber
1
new[] { (object) 0, (object) null, (object) false }
Homero Barbosa
sumber