単一の object[] を params object[] に渡す方法
質問
次のような params object[] を取るメソッドがあります。
void Foo(params object[] items)
{
Console.WriteLine(items[0]);
}
2 つのオブジェクト配列をこのメソッドに渡すと、正常に動作します。
Foo(new object[]{ (object)"1", (object)"2" }, new object[]{ (object)"3", (object)"4" } );
// Output: System.Object[]
しかし、単一の object[] を渡すと、 object[] を最初のパラメータとして取らず、代わりに、私が 1 つずつ渡したいようにすべての要素を受け取ります。
Foo(new object[]{ (object)"1", (object)"2" });
// Output: 1, expected: System.Object[]
単一の object[] を最初の引数として params 配列に渡すにはどうすればよいですか?
解決
単純な型キャストにより、コンパイラーはこの場合の意味を確実に認識できます。
Foo((object)new object[]{ (object)"1", (object)"2" }));
配列はオブジェクトのサブタイプであるため、これはすべてうまくいきます。ちょっと奇妙な解決策ですが、私は同意します。
他のヒント
の params
パラメーター修飾子は、呼び出し元に複数の引数をメソッドに渡すためのショートカット構文を提供します。メソッドを呼び出す方法は 2 つあります。 params
パラメータ:
1) パラメーター型の配列を使用して呼び出します。この場合、 params
キーワードは効果がなく、配列はメソッドに直接渡されます。
object[] array = new[] { "1", "2" };
// Foo receives the 'array' argument directly.
Foo( array );
2) または、引数の拡張リストを使用して呼び出します。この場合、コンパイラは引数のリストを一時配列に自動的にラップし、それをメソッドに渡します。
// Foo receives a temporary array containing the list of arguments.
Foo( "1", "2" );
// This is equivalent to:
object[] temp = new[] { "1", "2" );
Foo( temp );
オブジェクト配列をメソッドに渡すには、「params object[]
" パラメータでは、次のいずれかを実行できます。
1) で述べたように、ラッパー配列を手動で作成し、それをメソッドに直接渡します。 ラセフク:
Foo( new object[] { array } ); // Equivalent to calling convention 1.
2) または、引数を次のようにキャストします。 object
, で述べたように、 アダム, この場合、コンパイラはラッパー配列を作成します。
Foo( (object)array ); // Equivalent to calling convention 2.
ただし、メソッドの目的が複数のオブジェクト配列を処理することである場合は、明示的に "params object[][]
"パラメータ。これにより、複数の配列を引数として渡すことができます。
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 );
編集: Raymond Chen は、この動作とそれが C# 仕様にどのように関連するかを次の文書で説明しています。 新しい投稿.
これは、LINQ を使用した 1 行のソリューションです。
var elements = new String[] { "1", "2", "3" };
Foo(elements.Cast<object>().ToArray())
次のように、それを別の object[] 配列にカプセル化する必要があります。
Foo(new Object[] { new object[]{ (object)"1", (object)"2" }});
オプションの 1 つは、それを別の配列にラップすることです。
Foo(new object[]{ new object[]{ (object)"1", (object)"2" } });
ちょっと見苦しいですが、各項目は配列であるため、キャストするだけで問題を解決することはできません...たとえば、それが Foo(params object items) の場合は、次のようにすることができます。
Foo((object) new object[]{ (object)"1", (object)"2" });
あるいは、単一の配列だけを取る Foo の別のオーバーロードされたインスタンスを定義してみることもできます。
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 });
}
new[] { (object) 0, (object) null, (object) false }
この問題を解決する別の方法 (あまり良い習慣ではありませんが、見た目は美しいです):
static class Helper
{
public static object AsSingleParam(this object[] arg)
{
return (object)arg;
}
}
使用法:
f(new object[] { 1, 2, 3 }.AsSingleParam());