Cómo pasar un solo objeto [] a un objeto params []

124

Tengo un método que toma params object [] como:

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

Cuando paso dos matrices de objetos a este método, funciona bien:

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

Pero cuando paso un solo objeto [], no toma mi objeto [] como primer parámetro, sino que toma todos sus elementos como si quisiera pasarlos uno por uno:

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

¿Cómo paso un solo objeto [] como primer argumento a una matriz de parámetros?

Serhat Ozgel
fuente

Respuestas:

99

Un simple typecast asegurará que el compilador sepa lo que quiere decir en este caso.

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

Como una matriz es un subtipo de objeto, todo esto funciona. Aunque es una solución extraña, estoy de acuerdo.

Adam Wright
fuente
2
la forma en que funcionan los params parece innecesaria, y el diseño subóptimo de C #, dado lo que estamos acostumbrados en otros idiomas. los parámetros podrían haberse hecho para aceptar solo un formulario, y se podría agregar una función de difusión que beneficiaría a todo el idioma, no solo este caso. por ejemplo, podríamos forzar que todas las llamadas param sean Foo (obj [0], obj [1]), y luego tener un operador separado que permita Foo (... obj).
whitneyland
1
Me di cuenta de que no había dejado en claro que tengo un gran respeto por Anders Hejlsberg, es uno de los mejores diseñadores de idiomas del mundo. pero podemos pensar en las mejoras en el trabajo de cualquier persona dada la suficiente retrospectiva, de ahí la tecnología.
whitneyland
74

El paramsmodificador de parámetros proporciona a los llamantes una sintaxis de acceso directo para pasar múltiples argumentos a un método. Hay dos formas de llamar a un método con un paramsparámetro:

1) Llamar con una matriz del tipo de parámetro, en cuyo caso la paramspalabra clave no tiene efecto y la matriz se pasa directamente al método:

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

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

2) O, llamando con una lista extendida de argumentos, en cuyo caso el compilador ajustará automáticamente la lista de argumentos en una matriz temporal y la pasará al método:

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

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


Para pasar una matriz de objetos a un método con un params object[]parámetro " ", puede:

1) Cree una matriz de contenedor manualmente y páselo directamente al método, como lo menciona lassevk :

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

2) O bien, eche el argumento a object, como lo mencionó Adam , en cuyo caso el compilador creará la matriz de envoltura para usted:

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


Sin embargo, si el objetivo del método es procesar múltiples matrices de objetos, puede ser más fácil declararlo con un " params object[][]" parámetro explícito . Esto le permitiría pasar múltiples matrices como argumentos:

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

Editar: Raymond Chen describe este comportamiento y cómo se relaciona con la especificación C # en una nueva publicación .

Emperador XLII
fuente
8

Esta es una solución de una línea que involucra LINQ.

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

Necesita encapsularlo en otra matriz object [], como esta:

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

Otra forma de resolver este problema (no es tan buena práctica pero se ve hermosa):

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

Uso:

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

Una opción es que puede envolverlo en otra matriz:

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

Es feo, pero dado que cada elemento es una matriz, no puedes simplemente lanzarlo para que el problema desaparezca ... como si fuera Foo (elementos de objeto params), entonces simplemente podrías hacer:

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

Alternativamente, podría intentar definir otra instancia sobrecargada de Foo que toma solo una matriz:

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