Pourquoi utiliser le mot-clé params?

336

Je sais que c'est une question fondamentale, mais je n'ai pas trouvé de réponse.

Pourquoi l'utiliser? si vous écrivez une fonction ou une méthode qui l'utilise, lorsque vous la supprimez, le code fonctionnera toujours parfaitement, à 100% comme sans elle. Par exemple:

Avec params:

static public int addTwoEach(params int[] args)
{
    int sum = 0;
    foreach (var item in args)
        sum += item + 2;
    return sum;
}

Sans param:

static public int addTwoEach(int[] args)
{
    int sum = 0;
    foreach (var item in args)
       sum += item + 2;
    return sum;
}
MasterMastic
la source
62
Le code de la méthode elle-même fonctionnera toujours parfaitement ... le code appelant pourrait bien ne pas ...
Jon Skeet
7
params mot clé signifie des paramètres OPTIONNELS qui peuvent être passés ou non à la méthode. Un tableau sans mot clé params signifie que vous DEVEZ passer l'argument tableau à la méthode.
Ailayna Entarria
Le langage Python implémente le même concept si doucement avec un *paramètre préfixé asterisk ( ) comme mentionné ici .
RBT

Réponses:

485

Avecparams vous pouvez appeler votre méthode comme ceci:

addTwoEach(1, 2, 3, 4, 5);

Sans params, vous ne pouvez pas.

De plus, vous pouvez appeler la méthode avec un tableau en tant que paramètre dans les deux cas :

addTwoEach(new int[] { 1, 2, 3, 4, 5 });

Autrement dit, paramsvous permet d'utiliser un raccourci lors de l'appel de la méthode.

Indépendant, vous pouvez considérablement raccourcir votre méthode:

public static int addTwoEach(params int[] args)
{
    return args.Sum() + 2 * args.Length;
}
Konrad Rudolph
la source
17
@Ken: Vous devrez peut-être importer l' System.Linqespace de noms :)
Ranhiru Jude Cooray
49
Ou renvoyer args.Sum (i => i + 2);
bornfromanegg
2
La somme avec un délégué, cependant, augmente la complexité du code compilé, qui pourrait potentiellement être moins performant. Pas vraiment pertinent dans cette situation particulière, car cela n'entraînerait aucune fermeture, mais cela vaut la peine de savoir ce que le compilateur fait réellement pour faire le meilleur choix.
Allen Clark Copeland Jr
2
Vous pouvez également utiliser return args.Select(x => x + 2).Sum();
bbvg
1
Lorsque vous ajoutez, paramsvous vous verrouillez à ajouter des arguments de méthode supplémentaires sans interrompre vos appelants ou la résolution de méthode.
M. Young
93

L'utilisation paramsvous permet d'appeler la fonction sans arguments. Sans params:

static public int addTwoEach(int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // throws an error

Comparez avec params:

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // returns 0

En règle générale, vous pouvez utiliser des paramètres lorsque le nombre d'arguments peut varier de 0 à l'infini et utiliser un tableau lorsque le nombre d'arguments varie de 1 à l'infini.

Vasya
la source
13
en fait, un tableau peut être vide. new int[0]. J'espère que cela t'aides! :)
vidstige
22

Il vous permet d'ajouter autant de paramètres de type de base dans votre appel que vous le souhaitez.

addTwoEach(10, 2, 4, 6)

alors qu'avec le second formulaire, vous devez utiliser un tableau comme paramètre

addTwoEach(new int[] {10,2,4,6})
okrumnow
la source
17

Un des dangers du paramsmot-clé est que, après le codage des appels à la méthode,

  1. quelqu'un supprime accidentellement / intentionnellement un ou plusieurs paramètres requis de la signature de méthode, et
  2. un ou plusieurs paramètres requis immédiatement avant le paramsparamètre avant le changement de signature étaient compatibles avec le paramsparamètre,

ces appels continueront à être compilés avec une ou plusieurs expressions précédemment destinées aux paramètres requis traités comme paramsparamètre facultatif . Je suis juste tombé sur le pire des cas: le paramsparamètre était de type object[].

Ceci est remarquable car les développeurs sont habitués à ce que le compilateur se tape les poignets avec le scénario beaucoup plus courant où les paramètres sont supprimés d'une méthode avec tous les paramètres requis (car le nombre de paramètres attendus changerait).

Pour moi, ça ne vaut pas le raccourci. (Type)[]sans paramsfonctionnera avec 0 à l'infini # de paramètres sans avoir besoin de remplacements. Le pire des cas est que vous devrez ajouter un , new (Type) [] {}aux appels là où il ne s'applique pas.

Btw, à mon humble avis, la pratique la plus sûre (et la plus lisible) consiste à:

  1. passer via les paramètres nommés (ce que nous pouvons maintenant faire même en C # ~ 2 décennies après avoir pu en VB; P) (parce que:

    1.1. c'est le seul moyen qui garantit la prévention des valeurs involontaires transmises aux paramètres après l'ordre des paramètres, le type compatible et / ou le changement de nombre après le codage des appels,

    1.2. il réduit ces chances après un changement de signification de paramètre, car le nouveau nom d'identifiant probable reflétant la nouvelle signification est juste à côté de la valeur qui lui est transmise,

    1.3. cela évite d'avoir à compter les virgules et à sauter d'avant en arrière de l'appel à la signature pour voir quelle expression est passée pour quel paramètre, et

    1.3.1. Soit dit en passant, cette raison à elle seule devrait être abondante (en termes d'éviter les violations fréquentes sujettes aux erreurs du principe DRY, juste pour lire le code sans parler de le modifier également ), mais cette raison peut être exponentiellement plus importante s'il y en a un / plus d'expressions transmises contenant elles-mêmes des virgules, c'est-à-dire des références de tableau multidimensionnel ou des appels de fonction multi-paramètres. Dans ce cas, vous ne pourriez même pas utiliser (ce qui, même si vous le pouviez, ajouterait toujours une étape supplémentaire par paramètre par appel de méthode) une fonction Rechercher toutes les occurrences dans une sélection dans votre éditeur pour automatiser le comptage des virgules pour vous.

    1.4. si vous devez utiliser des paramètres facultatifs ( paramsou non), cela vous permet de rechercher des appels où un paramètre facultatif particulier est passé (et donc, très probablement n'est pas ou au moins a la possibilité de ne pas être la valeur par défaut),

(REMARQUE: les raisons 1.2 et 1.3 peuvent faciliter et réduire les risques d'erreur même lors du codage des appels initiaux, sans mentionner quand les appels doivent être lus et / ou modifiés.))

et

  1. faites-le UN - PARAMÈTRE - PAR - LIGNE pour une meilleure lisibilité (car:

    2.1. c'est moins encombré, et

    2.2. cela évite d'avoir à faire défiler vers la droite et l'arrière vers la gauche (et de le faire PAR LIGNE, car la plupart des mortels ne peuvent pas lire la partie gauche de plusieurs lignes, faire défiler vers la droite et lire la partie droite)).

    2.3. il est conforme à la "meilleure pratique" que nous avons déjà développée pour les déclarations d'affectation, car chaque paramètre transmis est essentiellement une déclaration d'affectation (attribution d'une valeur ou d'une référence à une variable locale). Tout comme ceux qui suivent la dernière «meilleure pratique» dans le style de codage ne rêveraient pas de coder plusieurs déclarations d'affectation par ligne, nous ne devrions probablement pas (et une fois que la «meilleure pratique» ne rattrapera pas mon «génie»; P ) le faire lors du passage des paramètres.

REMARQUES :

  1. Passer des variables dont les noms reflètent les paramètres n'aide pas lorsque:

    1.1. vous passez des constantes littérales (c.-à-d. un simple 0/1, faux / vrai ou nul pour lequel même les «meilleures pratiques» peuvent ne pas exiger que vous utilisiez une constante nommée et leur fonction ne peut pas être facilement déduite du nom de la méthode ),

    1.2. la Méthode est de niveau nettement inférieur / plus générique que l'Appelant de telle sorte que vous ne voudriez pas / ne pourriez pas nommer vos Variables de la même / similaire aux Paramètres (ou vice versa), ou

    1.3. vous êtes la réordonnancement / remplacement des paramètres dans la signature qui peut donner lieu à des appels antérieurs encore parce que les Compiler types se trouvent être encore compatibles.

  2. Avoir une fonction d'enveloppement automatique comme VS n'élimine qu'UNE (# 2.2) des 8 raisons que j'ai données ci-dessus. Avant aussi tard que VS 2015, il n'avait PAS d'indentation automatique (!?! Vraiment, MS?!?), Ce qui augmente la gravité de la raison n ° 2.1.

VS devrait avoir une option qui génère des extraits d'appel de méthode avec des paramètres nommés (un par ligne bien sûr; P) et une option de compilateur qui nécessite des paramètres nommés (similaire dans son concept à Option Explicit dans VB qui, au fait, l'exigence de était prolly une fois pensée tout aussi scandaleux, mais est désormais exigé par les «meilleures pratiques»). En fait, "de retour dans monjour ";), en 1991, quelques mois seulement après ma carrière, avant même d'utiliser (ou même d'avoir vu) un langage avec des paramètres nommés, j'avais l'anti-mouton /" juste parce que vous pouvez, ne veut pas dire que vous devriez " / ne pas aveuglément "couper les extrémités du rôti" sens suffisant pour le simuler (en utilisant des commentaires en ligne) sans avoir vu personne le faire. Ne pas avoir à utiliser les paramètres nommés (ainsi que toute autre syntaxe qui sauve "" précieux "" code source) est une relique de l'ère de la carte perforée lorsque la plupart de ces syntaxes ont commencé. Il n'y a aucune excuse pour cela avec du matériel moderne et des IDE et des logiciels beaucoup plus complexes où la lisibilité est beaucoup, BEAUCOUP , BEAUCOUPplus important. "Le code est lu beaucoup plus souvent qu'il n'est écrit". Tant que vous ne dupliquez pas le code non mis à jour automatiquement, chaque frappe enregistrée est susceptible de coûter plus cher lorsque quelqu'un (même vous-même) essaie de le lire plus tard.

À M
la source
2
Je ne comprends pas. Pourquoi ne pouvez-vous pas simplement imposer qu'il y en ait au moins un? Même sans paramètres, rien ne vous empêche de passer nullou new object[0]comme argument.
Casey
Il est probablement trop dangereux d'avoir des paramètres requis avant celui facultatif (dans le cas où un ou plusieurs de ces paramètres requis sont supprimés après le codage des appels). C'est peut-être pourquoi je n'ai jamais vu les paramètres requis avant le paramètre facultatif dans l'exemple de code dans les documents sur les paramètres facultatifs. Btw, à mon humble avis, la pratique la plus sûre (et la plus lisible) consiste à passer par des paramètres nommés (ce que nous pouvons maintenant faire même en C # ~ 2 décennies après avoir pu le faire en VB). VS doit avoir une option qui génère des extraits d'appel de méthode avec des paramètres nommés (et ce, 1 paramètre par ligne).
Tom
Je ne sais pas vraiment ce que tu veux dire. La seule façon dont vous pouvez avoir les paramètres requis et facultatifs est de spécifier d'abord tous ceux requis.
Casey
1
Ex. Je déclare myMethodcomme void myMethod(int requiredInt, params int[] optionalInts). I / quelqu'un d' autre un code / plusieurs appels, par exemple myMethod(1), myMethod(1, 21), myMethod(1, 21, 22). Je change myMethodpour être void myMethod(params int[] optionalInts). Tous ces appels seront toujours compilés sans erreur même si leurs 1ers paramètres (les "1") n'étaient clairement pas destinés à être passés en tant que 1er élément du optionalIntsparamètre.
Tom
Oh. Eh bien, OK, dans ce cas particulier, il peut être mal avisé. Je ne pense pas qu'il y ait aucune raison de l'éviter si vous avez besoin d'une chaîne et de 0 à plusieurs entrées ou autre.
Casey
10

Pas besoin de créer des méthodes de surcharge, utilisez simplement une seule méthode avec des paramètres comme indiqué ci-dessous

// Call params method with one to four integer constant parameters.
//
int sum0 = addTwoEach();
int sum1 = addTwoEach(1);
int sum2 = addTwoEach(1, 2);
int sum3 = addTwoEach(3, 3, 3);
int sum4 = addTwoEach(2, 2, 2, 2);
electricbah
la source
Merci pour votre contribution, mais je ne pense pas que ce type de surcharge serait une solution du tout, car avec paramsou sans nous passerions simplement un type de collection pour couvrir n'importe quel nombre de collections.
MasterMastic
Vous avez raison dans une certaine mesure, mais ce qui le rend cool, c'est une surcharge sans paramètre d'entrée, par exemple int sum1 = addTwoEach ();
electricbah
5

params vous permet également d'appeler la méthode avec un seul argument.

private static int Foo(params int[] args) {
    int retVal = 0;
    Array.ForEach(args, (i) => retVal += i);
    return retVal;
}

c'est à dire Foo(1);au lieu de Foo(new int[] { 1 });. Peut être utile pour la sténographie dans les scénarios où vous devrez peut-être passer une seule valeur plutôt qu'un tableau entier. Il est toujours géré de la même manière dans la méthode, mais donne des bonbons pour appeler de cette façon.

David Anderson
la source
5

L'ajout du mot-clé params lui-même montre que vous pouvez passer plusieurs nombres de paramètres tout en appelant cette méthode, ce qui n'est pas possible sans l'utiliser. Pour être plus précis:

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

Lorsque vous appellerez la méthode ci-dessus, vous pouvez l'appeler de l'une des manières suivantes:

  1. addTwoEach()
  2. addTwoEach(1)
  3. addTwoEach(new int[]{ 1, 2, 3, 4 })

Mais lorsque vous supprimerez le mot-clé params, seule la troisième manière des méthodes indiquées ci-dessus fonctionnera correctement. Pour les 1er et 2e cas, vous obtiendrez une erreur.

Ashwini
la source
0

Encore une chose importante à souligner. Il vaut mieux l'utiliser paramscar il est meilleur pour les performances. Lorsque vous appelez une méthode avec un paramsargument et ne lui passez rien:

public void ExampleMethod(params string[] args)
{
// do some stuff
}

appel:

ExampleMethod();

Ensuite, une nouvelle version du .Net Framework fait cela (à partir du .Net Framework 4.6):

ExampleMethod(Array.Empty<string>());

Cet Array.Emptyobjet peut être réutilisé par le framework ultérieurement, il n'est donc pas nécessaire de faire des allocations redondantes. Ces allocations se produisent lorsque vous appelez cette méthode comme ceci:

 ExampleMethod(new string[] {});
Beniamin Makal
la source
0

Cela peut sembler stupide, mais Params n'autorise pas les tableaux multidimensionnels. Alors que vous pouvez passer un tableau multidimensionnel à une fonction.

Manoj Kumar
la source
0

Un autre exemple

public IEnumerable<string> Tokenize(params string[] words)
{
  ...
}

var items = Tokenize(product.Name, product.FullName, product.Xyz)
skjagini
la source