Comment passer un seul objet [] à un objet params []

124

J'ai une méthode qui prend un objet params [] tel que:

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

Lorsque je passe deux tableaux d'objets à cette méthode, cela fonctionne bien:

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

Mais quand je passe un seul objet [], il ne prend pas mon objet [] comme premier paramètre, à la place il prend tous ses éléments comme je voulais les passer un par un:

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

Comment passer un seul objet [] comme premier argument à un tableau de paramètres?

Serhat Ozgel
la source

Réponses:

99

Un simple typage garantira que le compilateur sait ce que vous voulez dire dans ce cas.

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

Comme un tableau est un sous-type d'objet, tout fonctionne. Une solution assez étrange, je suis d'accord

Adam Wright
la source
2
la façon dont les params fonctionne semble inutile, et la conception c # sous-optimale, étant donné ce à quoi nous nous sommes habitués dans d'autres langages. params aurait pu être fait pour n'accepter qu'une seule forme, et une fonctionnalité de type propagation pourrait être ajoutée qui profiterait à l'ensemble du langage, pas seulement à ce cas. par exemple, nous pourrions forcer tous les appels de paramètres à être Foo (obj [0], obj [1]), puis avoir un opérateur de propagation séparé autorisant Foo (... obj).
whitneyland
1
réalisé que je n'avais pas dit clairement que j'avais un grand respect pour anders hejlsberg, il est l'un des meilleurs designers linguistiques au monde. mais nous pouvons penser à des améliorations au travail de n'importe qui avec suffisamment de recul, d'où la technologie.
whitneyland
74

Le paramsmodificateur de paramètre donne aux appelants une syntaxe de raccourci pour passer plusieurs arguments à une méthode. Il existe deux façons d'appeler une méthode avec un paramsparamètre:

1) Appel avec un tableau du type paramètre, auquel cas le paramsmot - clé n'a aucun effet et le tableau est passé directement à la méthode:

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

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

2) Ou, en appelant avec une liste étendue d'arguments, auquel cas le compilateur encapsulera automatiquement la liste d'arguments dans un tableau temporaire et le passera à la méthode:

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

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


Pour passer un tableau d'objets à une méthode avec un params object[]paramètre " ", vous pouvez soit:

1) Créez un tableau de wrapper manuellement et passez-le directement à la méthode, comme mentionné par lassevk :

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

2) Ou, transtypez l'argument en object, comme mentionné par Adam , auquel cas le compilateur créera le tableau wrapper pour vous:

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


Cependant, si le but de la méthode est de traiter plusieurs tableaux d'objets, il peut être plus facile de le déclarer avec un params object[][]paramètre explicite " ". Cela vous permettrait de passer plusieurs tableaux comme arguments:

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

Edit: Raymond Chen décrit ce comportement et comment il se rapporte à la spécification C # dans un nouvel article .

Empereur XLII
la source
8

Il s'agit d'une solution en une ligne impliquant LINQ.

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

Vous devez l'encapsuler dans un autre tableau d'objets [], comme ceci:

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

Une autre façon de résoudre ce problème (ce n'est pas une bonne pratique mais ça a l'air beau):

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

Usage:

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

Une option est que vous pouvez l'envelopper dans un autre tableau:

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

Un peu moche, mais comme chaque élément est un tableau, vous ne pouvez pas simplement le lancer pour faire disparaître le problème ... comme s'il s'agissait de Foo (éléments d'objet params), alors vous pourriez simplement faire:

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

Vous pouvez également essayer de définir une autre instance surchargée de Foo qui ne prend qu'un seul tableau:

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