Come passare un singolo oggetto [] a un oggetto params []


124

Ho un metodo che accetta params object [] come:

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

Quando passo due matrici di oggetti a questo metodo, funziona benissimo:

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

Ma quando passo un singolo oggetto [], non prende il mio oggetto [] come primo parametro, invece prende tutti i suoi elementi come se volessi passarli uno per uno:

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

Come faccio a passare un singolo oggetto [] come primo argomento a un array di parametri?

Risposte:


99

Un semplice typecast assicurerà che il compilatore sappia cosa intendi in questo caso.

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

Dato che un array è un sottotipo di oggetto, tutto funziona. Un po 'di una strana soluzione, sono d'accordo.


2
il modo in cui funziona params sembra superfluo, e il design c # non ottimale, dato ciò a cui siamo abituati in altre lingue. si sarebbe potuto fare in modo che i parametri accettassero solo un modulo e si potesse aggiungere una funzione simile a diffusione che andrebbe a beneficio dell'intera lingua, non solo di questo caso. per esempio, potremmo forzare tutte le chiamate param ad essere Foo (obj [0], obj [1]), e quindi avere un operatore di spread separato che consenta Foo (... obj).
Whitneyland,

1
ho capito che non avevo chiarito di avere un grande rispetto per Anders Hejlsberg, è uno dei migliori designer di lingue al mondo. ma possiamo pensare a miglioramenti del lavoro di chiunque, con sufficiente senno di poi, quindi la tecnologia.
Whitneyland,

74

Il paramsmodificatore di parametro fornisce ai chiamanti una sintassi del collegamento per passare più argomenti a un metodo. Esistono due modi per chiamare un metodo con un paramsparametro:

1) Chiamata con un array del tipo di parametro, nel qual caso la paramsparola chiave non ha alcun effetto e l'array viene passato direttamente al metodo:

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

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

2) Oppure, chiamando con un elenco esteso di argomenti, nel qual caso il compilatore avvolgerà automaticamente l'elenco di argomenti in un array temporaneo e lo passerà al metodo:

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

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


Per passare un array di oggetti a un metodo con un params object[]parametro " ", è possibile:

1) Creare manualmente un array wrapper e passarlo direttamente al metodo, come indicato da lassevk :

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

2) Oppure, cast l'argomento object, come menzionato da Adam , nel qual caso il compilatore creerà l'array wrapper per te:

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


Tuttavia, se l'obiettivo del metodo è elaborare più array di oggetti, potrebbe essere più semplice dichiararlo con un params object[][]parametro " " esplicito . Ciò consentirebbe di passare più array come argomenti:

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

Modifica: Raymond Chen descrive questo comportamento e come si collega alla specifica C # in un nuovo post .


8

Questa è una soluzione a una riga che coinvolge LINQ.

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

3

È necessario incapsularlo in un altro array oggetto [], in questo modo:

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

2

Un altro modo per risolvere questo problema (non è una buona pratica ma sembra bello):

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

Uso:

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

1

Un'opzione è che puoi avvolgerlo in un altro array:

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

Un po 'brutto, ma dato che ogni oggetto è un array, non puoi semplicemente lanciarlo per far sparire il problema ... come se fosse Foo (oggetti oggetto params), quindi potresti semplicemente fare:

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

In alternativa, potresti provare a definire un'altra istanza sovraccarica di Foo che richiede solo un singolo array:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.