Perché usare la parola chiave params?


336

So che questa è una domanda di base, ma non sono riuscito a trovare una risposta.

Perché usarlo se scrivi una funzione o un metodo che la utilizza, quando la rimuovi il codice funzionerà comunque perfettamente, al 100% come senza di essa. Per esempio:

Con i parametri:

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

Senza parametri:

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

62
Il codice del metodo stesso funzionerà ancora perfettamente ... il codice chiamante potrebbe anche non ...
Jon Skeet,

7
parola chiave params significa parametri OPZIONALI che possono essere passati o meno al Metodo. Un array con la parola chiave out params significa che DEVI passare l'argomento array al metodo.
Ailayna Entarria,

Il linguaggio Python implementa lo stesso concetto in modo così dolce con un *parametro prefisso asterisco ( ) come menzionato qui .
RBT,

Risposte:


485

Conparams te puoi chiamare il tuo metodo in questo modo:

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

Senza params, non puoi.

Inoltre, è possibile chiamare il metodo con un array come parametro in entrambi i casi :

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

Cioè, paramsconsente di utilizzare un collegamento quando si chiama il metodo.

Non correlato, puoi ridurre drasticamente il tuo metodo:

public static int addTwoEach(params int[] args)
{
    return args.Sum() + 2 * args.Length;
}

17
@Ken: potrebbe essere necessario importare lo System.Linqspazio dei nomi :)
Ranhiru Jude Cooray,

49
Oppure restituisci args.Sum (i => i + 2);
bornfromanegg,

2
La somma con un delegato, tuttavia, aumenta la complessità del codice compilato, che potrebbe potenzialmente essere meno performante. Non molto rilevante in questa particolare situazione, in quanto non comporterebbe alcuna chiusura, ma vale la pena sapere cosa sta effettivamente facendo il compilatore per fare la scelta migliore.
Allen Clark Copeland Jr,

2
Puoi anche usare return args.Select(x => x + 2).Sum();
bbvg

1
Quando aggiungi paramsti blocchi dall'aggiunta di argomenti di metodo aggiuntivi senza interrompere i chiamanti o la risoluzione del metodo.
Mr. Young

93

L'utilizzo paramsconsente di chiamare la funzione senza argomenti. Senza params:

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

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

    return sum;
}

addtwoEach(); // throws an error

Confronta con params:

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

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

    return sum;
}

addtwoEach(); // returns 0

In genere, è possibile utilizzare i parametri quando il numero di argomenti può variare da 0 a infinito e utilizzare un array quando il numero di argomenti varia da 1 a infinito.


13
in realtà un array può essere vuoto. new int[0]. spero che questo ti aiuti! :)
vidstige,

22

Ti consente di aggiungere tutti i parametri del tipo di base nella chiamata che desideri.

addTwoEach(10, 2, 4, 6)

mentre con il secondo modulo devi usare un array come parametro

addTwoEach(new int[] {10,2,4,6})

17

Un pericolo con paramsKeyword è, se dopo che le Chiamate al metodo sono state codificate,

  1. qualcuno rimuove accidentalmente / intenzionalmente uno / più parametri richiesti dalla firma del metodo e
  2. uno / più parametri richiesti immediatamente prima del paramsparametro prima della modifica della firma erano compatibili con il paramsparametro,

tali Chiamate continueranno a essere compilate con una / più espressioni precedentemente intese per i Parametri richiesti, trattate come paramsParametro opzionale . Ho appena incontrato il peggior caso possibile: il paramsparametro era di tipo object[].

Ciò è degno di nota perché gli sviluppatori sono abituati al compilatore a schiaffeggiarsi i polsi con lo scenario molto, molto più comune in cui i parametri vengono rimossi da un metodo con tutti i parametri richiesti (poiché il numero di parametri previsti cambierebbe).

Per me, non vale la scorciatoia. (Type)[]senza paramsfunzionerà con 0 all'infinito # di parametri senza bisogno di sostituzioni. Il caso peggiore è che dovrai aggiungere un , new (Type) [] {}a Chiamate dove non si applica.

A proposito, imho, la pratica più sicura (e più leggibile) è:

  1. passare tramite Named Parameters (cosa che ora possiamo fare anche in C # ~ 2 decenni dopo potremmo in VB; P) (perché:

    1.1. è l' unico modo che garantisce la prevenzione di valori non intenzionali passati ai parametri dopo che l'ordine dei parametri, il tipo compatibile e / o il conteggio cambiano dopo che le chiamate sono state codificate,

    1.2. si riduce quelle probabilità dopo un cambiamento di significato dei parametri, perché il probabile nuovo nome identificativo che riflette il nuovo significato è proprio accanto al valore che si passa ad esso,

    1.3. evita di dover contare le virgole e saltare avanti e indietro da chiamata a firma per vedere quale espressione viene passata per quale parametro e

    1.3.1. A proposito, questo motivo da solo dovrebbe essere abbondante (in termini di evitare frequenti violazioni soggette a errori del principio DRY solo per leggere il codice per non parlare anche di modificarlo ), ma questo motivo può essere esponenzialmente più importante se ce ne sono uno / vengono trasmesse più espressioni che a loro volta contengono virgole, ad esempio riferimenti ad array multidimensionali o chiamate di funzioni a più parametri. In tal caso, non è nemmeno possibile utilizzare (che anche se fosse possibile, aggiungerebbe comunque un passaggio aggiuntivo per Parametro per Chiamata metodo) a Trova tutte le occorrenze in una funzione di selezione nel proprio editor per automatizzare il conteggio delle virgole.

    1.4. se è necessario utilizzare i parametri opzionali ( paramso meno), consente di cercare le chiamate in cui viene passato un determinato parametro facoltativo (e quindi, molto probabilmente non lo è o almeno ha la possibilità di non essere il valore predefinito),

(NOTA: i motivi 1.2 e 1.3 possono facilitare e ridurre le possibilità di errore anche durante la codifica delle Chiamate iniziali per non menzionare quando le Chiamate devono essere lette e / o modificate.))

e

  1. fallo ONE - PARAMETER - PER - LINE per una migliore leggibilità (perché:

    2.1. è meno ingombra, e

    2.2. evita di dover scorrere a destra e indietro a sinistra (e di farlo PER - LINE, poiché la maggior parte dei mortali non può leggere la parte sinistra di più righe, scorrere a destra e leggere la parte destra)).

    2.3. è coerente con la "Best Practice" in cui ci siamo già evoluti per le dichiarazioni di assegnazione, poiché ogni parametro passato è essenzialmente un'istruzione di assegnazione (che assegna un valore o un riferimento a una variabile locale). Proprio come coloro che seguono l' ultima "Best Practice" in Coding Style non sognerebbero di codificare più Dichiarazioni di assegnazione per riga, probabilmente non dovremmo (e non una volta che "Best Practice" raggiungerà il mio "genio"; P ) quando passa i parametri.

NOTE :

  1. Passare in variabili i cui nomi rispecchiano i parametri 'non aiuta quando:

    1.1. stai passando in Costanti letterali (vale a dire un semplice 0/1, falso / vero o nullo per cui anche le "Best practice" potrebbero non richiedere l'utilizzo di una Costante nominata e il loro scopo non può essere facilmente dedotto dal nome del metodo ),

    1.2. il Metodo è significativamente più basso / più generico del Caller in modo tale che tu non voglia / sia in grado di nominare le tue Variabili uguali / simili ai Parametri (o viceversa), oppure

    1.3. stai riordinando / sostituendo i parametri nella firma che potrebbero causare la compilazione di chiamate precedenti perché i tipi sono ancora compatibili.

  2. Avere una funzione di avvolgimento automatico come VS elimina UNO (# 2.2) degli 8 motivi che ho indicato sopra. Prima del VS 2015, NON rientrava automaticamente (!?! Davvero, SM?!?) Che aumenta la gravità della ragione # 2.1.

VS dovrebbe avere un'opzione che genera frammenti di chiamata di metodo con parametri nominati (uno per linea ovviamente; P) e un'opzione del compilatore che richiede parametri nominati (simile nel concetto a Option Explicit in VB che, tra l'altro, il requisito di era prolly una volta pensato ugualmente oltraggioso ma ora è ampiamente richiesto da "'Best Practices'"). In effetti, "torna nel miogiorno ";), nel 1991, a pochi mesi dalla mia carriera, anche prima che usassi (o avessi persino visto) una lingua con Parametri nominati, avevo l'anti-pecorella /" solo perché puoi, non significa che dovresti " / non ciecamente "tagliare le estremità dell'arrosto" abbastanza da simularlo (usando commenti in linea) senza aver visto nessuno farlo. Non dover usare Named Parameters (così come altre sintassi che salvano "'prezioso'" tasti del codice sorgente) è una reliquia dell'era della Punch Card quando è iniziata la maggior parte di queste sintassi. Non ci sono scuse per questo con hardware e IDE moderni e software molto più complesso in cui la leggibilità è molto, MOLTO , MOLTOpiù importante. "Il codice viene letto molto più spesso di quanto sia scritto". Finché non stai duplicando il codice non auto-aggiornato, ogni sequenza di tasti salvata avrà un costo esponenzialmente maggiore quando qualcuno (anche te stesso) sta cercando di leggerlo in seguito.


2
Non capisco. Perché non puoi semplicemente imporre che ce ne sia almeno uno? Anche senza i parametri non c'è nulla che possa impedirti di passare nullo new object[0]come argomento.
Casey,

Probabilmente è semplicemente troppo pericoloso avere parametri richiesti prima di quello opzionale (nel caso in cui uno o più di quelli richiesti vengano rimossi dopo la codifica delle chiamate). Questo potrebbe essere il motivo per cui non ho mai visto i parametri richiesti prima del parametro facoltativo nel codice di esempio in qualsiasi documento sui parametri opzionali. A proposito, imho, la pratica più sicura (e più leggibile) è passare attraverso parametri nominati (cosa che ora possiamo fare anche in C # ~ 2 decenni dopo potremmo in VB). VS dovrebbe avere un'opzione che genera frammenti di chiamata di metodo con parametri denominati (e quindi fare 1 parametro per riga).
Tom

Non sono proprio sicuro di cosa tu voglia dire. L'unico modo in cui è possibile avere i parametri richiesti e quelli opzionali è specificare prima tutti quelli richiesti.
Casey

1
Ex. Dichiaro myMethodcome void myMethod(int requiredInt, params int[] optionalInts). I / qualcuno codici altro / più chiamate, vale a dire myMethod(1), myMethod(1, 21), myMethod(1, 21, 22). Cambio myMethodper essere void myMethod(params int[] optionalInts). Tutte queste chiamate verranno comunque compilate senza errori anche se i loro primi parametri (gli "1") non erano chiaramente destinati a essere passati come primo elemento del optionalIntsparametro.
Tom

Oh. Bene, OK, in quel caso particolare potrebbe essere sconsigliato. Non credo che ci sia alcun motivo per evitarlo se hai bisogno di una stringa e di 0-a-molti ints o altro.
Casey,

10

Non è necessario creare metodi di sovraccarico, basta usare un solo metodo con i parametri come mostrato di seguito

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

Grazie per il tuo contributo, ma non credo che questo tipo di sovraccarichi sarebbe una soluzione, dato che con paramso senza passeremmo un tipo di raccolta per coprire qualsiasi numero di raccolte.
MasterMastic

Hai ragione in una certa misura, ma ciò che lo rende interessante è un sovraccarico senza parametri di input, ad esempio int sum1 = addTwoEach ();
Electricalbah

5

params consente inoltre di chiamare il metodo con un singolo argomento.

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

cioè Foo(1);invece di Foo(new int[] { 1 });. Può essere utile per la stenografia negli scenari in cui potrebbe essere necessario passare un singolo valore anziché un intero array. È ancora gestito allo stesso modo nel metodo, ma dà alcune caramelle per chiamare in questo modo.


5

L'aggiunta della stessa parola chiave params mostra che è possibile passare più numeri di parametri mentre si chiama quel metodo che non è possibile senza usarlo. Per essere più specifici:

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

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

    return sum;
}

Quando chiamerai il metodo sopra puoi chiamarlo in uno dei seguenti modi:

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

Ma quando rimuoverai la parola chiave params solo il terzo modo dei modi indicati sopra funzionerà bene. Per il 1o e il 2o caso verrà visualizzato un errore.


0

Un'altra cosa importante deve essere evidenziata. È meglio usare paramsperché è migliore per le prestazioni. Quando chiami un metodo con paramsargomento e non gli passi nulla:

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

chiamata:

ExampleMethod();

Quindi una nuova versione di .Net Framework fa questo (da .Net Framework 4.6):

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

Questo Array.Empty oggetto può essere riutilizzato dal framework in un secondo momento, quindi non è necessario eseguire allocazioni ridondanti. Queste allocazioni si verificano quando si chiama questo metodo in questo modo:

 ExampleMethod(new string[] {});

0

Potrebbe sembrare stupido, ma Params non consente array multidimensionali. Considerando che è possibile passare un array multidimensionale a una funzione.


0

Un altro esempio

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

var items = Tokenize(product.Name, product.FullName, product.Xyz)
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.