So übergeben Sie ein einzelnes Objekt [] an ein params-Objekt []

124

Ich habe eine Methode, die params object [] verwendet, wie zum Beispiel:

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

Wenn ich dieser Methode zwei Objektarrays übergebe, funktioniert das einwandfrei:

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

Wenn ich jedoch ein einzelnes Objekt [] übergebe, wird mein Objekt [] nicht als erster Parameter verwendet, sondern es werden alle Elemente so verwendet, als ob ich sie einzeln übergeben wollte:

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

Wie übergebe ich ein einzelnes Objekt [] als erstes Argument an ein params-Array?

Serhat Ozgel
quelle

Antworten:

99

Ein einfacher Typecast stellt sicher, dass der Compiler weiß, was Sie in diesem Fall meinen.

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

Da ein Array ein Subtyp eines Objekts ist, funktioniert dies alles. Eine seltsame Lösung, da stimme ich zu.

Adam Wright
quelle
2
Die Art und Weise, wie params funktioniert, scheint unnötig und ein suboptimales c # -Design, wenn man bedenkt, wie wir es in anderen Sprachen gewohnt sind. params könnten so eingestellt werden, dass sie nur ein Formular akzeptieren, und es könnte eine Funktion hinzugefügt werden, die der gesamten Sprache zugute kommt, nicht nur in diesem Fall. Zum Beispiel könnten wir erzwingen, dass alle Parameteraufrufe Foo (obj [0], obj [1]) sind, und dann einen separaten Spread-Operator haben, der Foo (... obj) zulässt.
Whitneyland
1
Mir wurde klar, dass ich nicht klar gemacht hatte, dass ich großen Respekt vor anders hejlsberg habe. Er ist einer der besten Sprachdesigner der Welt. Aber wir können über Verbesserungen der Arbeit eines jeden nachdenken, wenn wir genug Rückblick haben, daher Technologie.
Whitneyland
74

Der paramsParametermodifikator gibt Aufrufern eine Verknüpfungssyntax zum Übergeben mehrerer Argumente an eine Methode. Es gibt zwei Möglichkeiten, eine Methode mit einem paramsParameter aufzurufen :

1) Aufruf mit einem Array vom Parametertyp. In diesem Fall hat das paramsSchlüsselwort keine Auswirkung und das Array wird direkt an die Methode übergeben:

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

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

2) Oder rufen Sie mit einer erweiterten Liste von Argumenten auf. In diesem Fall wird der Compiler die Liste der Argumente automatisch in ein temporäres Array einschließen und diese an die Methode übergeben:

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

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


Um ein Objektarray an eine Methode mit einem " params object[]" -Parameter zu übergeben, können Sie entweder:

1) Erstellen Sie manuell ein Wrapper-Array und übergeben Sie dieses direkt an die Methode, wie von lassevk erwähnt :

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

2) Oder setzen Sie das Argument auf object, wie von Adam erwähnt . In diesem Fall erstellt der Compiler das Wrapper-Array für Sie:

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


Wenn das Ziel der Methode jedoch darin besteht, mehrere Objektarrays zu verarbeiten, ist es möglicherweise einfacher, sie mit einem expliziten " params object[][]" -Parameter zu deklarieren . Auf diese Weise können Sie mehrere Arrays als Argumente übergeben:

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

Bearbeiten: Raymond Chen beschreibt dieses Verhalten und wie es sich auf die C # -Spezifikation in bezieht einem neuen Beitrag .

Kaiser XLII
quelle
8

Dies ist eine einzeilige Lösung mit LINQ.

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

Sie müssen es wie folgt in ein anderes Objekt [] -Array kapseln:

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

Ein anderer Weg, um dieses Problem zu lösen (es ist nicht so gute Praxis, sieht aber schön aus):

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

Verwendung:

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

Eine Option ist, dass Sie es in ein anderes Array einschließen können:

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

Etwas hässlich, aber da jedes Element ein Array ist, können Sie es nicht einfach umwandeln, um das Problem zu beheben. Wenn es beispielsweise Foo (params object items) wäre, könnten Sie einfach Folgendes tun:

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

Alternativ können Sie versuchen, eine andere überladene Instanz von Foo zu definieren, die nur ein einziges Array benötigt:

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