Come puoi usare parametri opzionali in C #?


493

Nota: questa domanda è stata posta in un momento in cui C # non supportava ancora parametri opzionali (ovvero prima di C # 4).

Stiamo creando un'API Web generata a livello di codice da una classe C #. La classe ha metodo GetFooBar(int a, int b)e l'API ha un metodo GetFooBarche accetta parametri di query simili &a=foo &b=bar.

Le classi devono supportare parametri opzionali, che non sono supportati in C # il linguaggio. Qual è l'approccio migliore?


7
Oppure attendere il rilascio di unitil C # 4.0. I parametri opzionali sono supportati.
Michea il

Risposte:


1055

Nessuno ha menzionato i parametri opzionali di C # 4.0 che funzionano così:

public void SomeMethod(int a, int b = 0)
{
   //some code
}

Modifica: so che al momento della domanda, C # 4.0 non esisteva. Ma questa domanda è ancora al primo posto in Google per "argomenti opzionali C #", quindi ho pensato: vale la pena trovare questa risposta. Scusate.


58
Al momento della domanda, C # 4.0 non esisteva.
Forrest Marvez,

91
Sì, trascurato questo, scusa. Ma questa domanda si colloca ancora al primo posto in Google per "argomenti opzionali C #", quindi comunque - vale la pena trovare questa risposta :)
Alex

45
Buon per te per fornire informazioni aggiornate. Idealmente, le risposte originali verrebbero aggiornate con informazioni aggiornate come C # 4.0. Credo che questo sia quello che avevano in mente i ragazzi SO, una mentalità Wiki, ma tutti hanno un po 'troppa paura di modificare la risposta di qualcun altro.
Rowan,

Qualcosa di interessante che ho scoperto con WebServices è che (certamente nel progetto che sto testando) tutti i valori booleari in una stringa di query sono opzionali per impostazione predefinita. Ovviamente sono predefiniti su FALSO.
Carlos P,

4
Vale la pena notare che i parametri opzionali devono essere posizionati dopo tutti i parametri non opzionali. cioè non puoi avere il vuoto pubblico SomeMethod (int b = 0, int a)
Andrew Meservy

129

Un'altra opzione è utilizzare la parola chiave params

public void DoSomething(params object[] theObjects)
{
  foreach(object o in theObjects)
  {
    // Something with the Objects…
  }
}

Chiamato come ...

DoSomething(this, that, theOther);

57
Questa risposta spiega la parola chiave params in 10 righe, MSDN non riesce ancora a farlo in 30. +1
Utente 2400

1
Grazie! Questo mi ha ispirato a scrivere una semplice funzione di registrazione (per il mio caso d'uso corrente): public void log (params object[] args){ StringBuilder sb = new StringBuilder(); for (int i = 0; i < args.Length; i++){ sb.Append("{"); sb.Append(i.ToString()); sb.Append("}"); sb.Append(" "); } String.Format(sb.ToString(),args).Dump(); }chiamata di esempio:log("...Done,",(watch.ElapsedMilliseconds/1000).ToString(),"s");
pfonseca,

potresti menzionarlo, Net 3.5 lo supporta? i documenti ufficiali non lo hanno menzionato.
T.Todua,

@ T.Todua - Non sono sicuro al 100% di ciò che stai chiedendo qui - dotnet framework 3.5 includeva C # v3.0 - la versione 3.0 supportava la parola chiave params, ma non aveva parametri opzionali, introdotti in C # v4.0 , incluso in dotnet framework 4.0
Tim Jarvis,

@ TimJarvis sì, quello che stavo chiedendo. tnx
T.Todua,

77

In C #, normalmente userei più forme del metodo:

void GetFooBar(int a) { int defaultBValue;  GetFooBar(a, defaultBValue); }
void GetFooBar(int a, int b)
{
 // whatever here
}

AGGIORNAMENTO: Questo sopra menzionato era il modo in cui ho fatto i valori predefiniti con C # 2.0. I progetti a cui sto lavorando ora utilizzano C # 4.0 che ora supporta direttamente parametri opzionali. Ecco un esempio che ho appena usato nel mio codice:

public EDIDocument ApplyEDIEnvelop(EDIVanInfo sender, 
                                   EDIVanInfo receiver, 
                                   EDIDocumentInfo info,
                                   EDIDocumentType type 
                                     = new EDIDocumentType(EDIDocTypes.X12_814),
                                   bool Production = false)
{
   // My code is here
}

1
Credo che non si possano chiamare costruttori con parametri predefiniti, devono essere compatibili con "tempo di compilazione", non "tempo di esecuzione" ... O sbaglio?
Alex

45

Da questo sito:

http://www.tek-tips.com/viewthread.cfm?qid=1500861&page=1

C # consente l'uso dell'attributo [Opzionale] (da VB, sebbene non funzionante in C #). Quindi puoi avere un metodo come questo:

using System.Runtime.InteropServices;
public void Foo(int a, int b, [Optional] int c)
{
  ...
}

Nel nostro wrapper API, rileviamo i parametri opzionali (ParameterInfo p.IsOptional) e impostiamo un valore predefinito. L'obiettivo è contrassegnare i parametri come facoltativi senza ricorrere a kludges come avere "facoltativo" nel nome del parametro.


4
Ma come usare la funzione Foo allora? Foo (1,1); foo (1,1, null) e foo (1,1, Missing.value) genereranno eccezioni
Bolu,

2
Strano, alcune risposte sopra sono molto meglio di così.
Maidot,

26

È possibile utilizzare il metodo di sovraccarico ...

GetFooBar ()
GetFooBar (int a)
GetFooBar (int a, int b)

Dipende dalle firme del metodo, nell'esempio che ho fornito manca solo il metodo "int b" perché avrebbe la stessa firma del metodo "int a".

È possibile utilizzare i tipi Nullable ...

GetFooBar (int? A, int? B)

È quindi possibile verificare, usando a.HasValue, per vedere se è stato impostato un parametro.

Un'altra opzione sarebbe quella di utilizzare un parametro "params".

GetFooBar (params object [] args)

Se si desidera utilizzare parametri con nome, è necessario creare un tipo per gestirli, anche se penso che ci sia già qualcosa di simile per le app Web.


24

È possibile utilizzare i parametri opzionali in C # 4.0 senza preoccupazioni. Se abbiamo un metodo come:

int MyMetod(int param1, int param2, int param3=10, int param4=20){....}

quando chiami il metodo, puoi saltare parametri come questo:

int variab = MyMethod(param3:50; param1:10);

C # 4.0 implementa una funzione chiamata "parametri nominati", puoi effettivamente passare i parametri con i loro nomi e, naturalmente, puoi passare i parametri nell'ordine che vuoi :)


20

Ciao mondo opzionale

Se si desidera che il runtime fornisca un valore di parametro predefinito, è necessario utilizzare la riflessione per effettuare la chiamata. Non carino come gli altri suggerimenti per questa domanda, ma compatibile con VB.NET.

using System;
using System.Runtime.InteropServices;
using System.Reflection;

namespace ConsoleApplication1
{
    class Class1
    {
        public static void sayHelloTo(
            [Optional,
            DefaultParameterValue("world")] string whom)
        {
            Console.WriteLine("Hello " + whom);
        }

        [STAThread]
        static void Main(string[] args)
        {
            MethodInfo mi = typeof(Class1).GetMethod("sayHelloTo");
            mi.Invoke(null, new Object[] { Missing.Value });
        }
    }
}

16

Un modo semplice che consente di omettere qualsiasi parametro in qualsiasi posizione , sta sfruttando i tipi nullable come segue:

public void PrintValues(int? a = null, int? b = null, float? c = null, string s = "")
{
    if(a.HasValue)
        Console.Write(a);
    else
        Console.Write("-");

    if(b.HasValue)
        Console.Write(b);
    else
        Console.Write("-");

    if(c.HasValue)
        Console.Write(c);
    else
        Console.Write("-");

    if(string.IsNullOrEmpty(s)) // Different check for strings
        Console.Write(s);
    else
        Console.Write("-");
}

Le stringhe sono già tipi nullable quindi non hanno bisogno del ? .

Una volta che hai questo metodo, le seguenti chiamate sono tutte valide :

PrintValues (1, 2, 2.2f);
PrintValues (1, c: 1.2f);
PrintValues(b:100);
PrintValues (c: 1.2f, s: "hello");
PrintValues();

Quando si definisce un metodo in questo modo, si ha la libertà di impostare solo i parametri desiderati nominandoli . Vedere il seguente collegamento per ulteriori informazioni sui parametri nominati e opzionali:

Argomenti nominati e opzionali (Guida per programmatori C #) @ MSDN


9

Sono d'accordo con stephenbayer. Ma poiché si tratta di un servizio Web, è più facile per l'utente finale utilizzare solo una forma del metodo web, piuttosto che utilizzare più versioni dello stesso metodo. Penso che in questa situazione i tipi nullable siano perfetti per i parametri opzionali.

public void Foo(int a, int b, int? c)
{
  if(c.HasValue)
  {
    // do something with a,b and c
  }
  else
  {
    // do something with a and b only
  }  
}

+1 Avvertimento però. Non prendere questa abitudine poiché può diventare davvero disordinato.
mhenrixon,

7

i parametri opzionali sono per i metodi. se hai bisogno di argomenti opzionali per una classe e sei:

  • usando c # 4.0: usare argomenti opzionali nel costruttore della classe, una soluzione che preferisco, poiché è più vicina a ciò che viene fatto con i metodi, quindi più facile da ricordare. ecco un esempio:

    class myClass
    {
        public myClass(int myInt = 1, string myString =
                               "wow, this is cool: i can have a default string")
        {
            // do something here if needed
        }
    }
  • usando versioni di c # precedenti a c # 4.0: dovresti usare il concatenamento del costruttore (usando: questa parola chiave), dove costruttori più semplici portano a un "costruttore principale". esempio:

    class myClass
    {
        public myClass()
        {
        // this is the default constructor
        }
    
        public myClass(int myInt)
            : this(myInt, "whatever")
        {
            // do something here if needed
        }
        public myClass(string myString)
            : this(0, myString)
        {
            // do something here if needed
        }
        public myClass(int myInt, string myString)
        {
            // do something here if needed - this is the master constructor
        }
    }

3

Il modo tipico in cui viene gestito in C # come menzionato da Stephen è di sovraccaricare il metodo. Creando più versioni del metodo con parametri diversi, si creano effettivamente parametri opzionali. Nei moduli con un numero inferiore di parametri, in genere si chiama il modulo del metodo con tutti i parametri che impostano i valori predefiniti nella chiamata a quel metodo.


2

Puoi sovraccaricare il tuo metodo. Un metodo contiene un parametro GetFooBar(int a)e l'altro contiene entrambi i parametri,GetFooBar(int a, int b)


2

Uso di sovraccarichi o utilizzo di C # 4.0 o successivo

 private void GetVal(string sName, int sRoll)
 {
   if (sRoll > 0)
   {
    // do some work
   }
 }

 private void GetVal(string sName)
 {
    GetVal("testing", 0);
 }

1

Per un numero maggiore di parametri opzionali, è possibile utilizzare un singolo parametro di Dizionario con il metodo ContainsKey. Mi piace questo approccio perché mi permette di passare un Elenco o una T individualmente senza dover creare un altro metodo (bello se i parametri devono essere usati come filtri, per esempio).

Esempio (il nuovo dizionario <stringa, Oggetto> () verrebbe passato se non si desidera alcun parametro facoltativo):

public bool Method(string ParamA, Dictionary<string,Object> AddlParams) {
    if(ParamA == "Alpha" && (AddlParams.ContainsKey("foo") || AddlParams.ContainsKey("bar"))) {
        return true;
    } else {
        return false;
    }
}

0

Invece di parametri predefiniti, perché non solo costruire una classe di dizionario dal passaggio di querystring .. un'implementazione che è quasi identica al modo in cui i moduli asp.net funzionano con le querystring.

cioè Request.QueryString ["a"]

Questo disaccoppierà la classe foglia dal codice factory / boilerplate.


Potresti anche voler controllare i servizi Web con ASP.NET . I servizi Web sono un'API Web generata automaticamente tramite attributi nelle classi C #.


0

Un po 'tardi alla festa, ma stavo cercando la risposta a questa domanda e alla fine ho trovato un altro modo per farlo. Dichiarare i tipi di dati per gli arg facoltativi del metodo Web in uso come XmlNode. Se l'arg opzionale viene omesso, questo verrà impostato su null e se è presente è possibile ottenere il valore di stringa chiamando arg.Value, ovvero,

[WebMethod]
public string Foo(string arg1, XmlNode optarg2)
{
    string arg2 = "";
    if (optarg2 != null)
    {
        arg2 = optarg2.Value;
    }
    ... etc
}

La cosa decente di questo approccio è che la home page generata da .NET per ws mostra ancora la lista degli argomenti (anche se perdi le comode caselle di immissione del testo per i test).


3
È meglio che usare tipi nullable?
Kirk Broadhurst,

0

Ho un servizio web da scrivere che accetta 7 parametri. Ognuno è un attributo di query facoltativo a un'istruzione sql racchiusa da questo servizio Web. Quindi vengono in mente due soluzioni alternative ai parametri non opzionali ... entrambi piuttosto scadenti:

metodo1 (parametro 1, parametro 2, parametro 3, parametro 4, parametro 5, parametro 6, parametro 7) metodo 1 (parametro 1, parametro 2, parametro 3, parametro 4, parametro 5, parametro 6) metodo 1 (parametro 1, parametro 2, parametro 3, parametro 4, parametro 5, parametro 7 ) ... inizia a vedere l'immagine. In questo modo sta la follia. Troppe combinazioni.

Ora per un modo più semplice che sembra imbarazzante ma che dovrebbe funzionare: method1 (param1, bool useParam1, param2, bool useParam2, ecc ...)

Questa è una chiamata di metodo, sono richiesti valori per tutti i parametri e gestirà ogni caso al suo interno. È anche chiaro come usarlo dall'interfaccia.

È un trucco, ma funzionerà.


2
Ecco perché esistono parametri nullable.
Kirk Broadhurst,

0

Ho dovuto farlo in un servizio Web VB.Net 2.0. Ho finito per specificare i parametri come stringhe, quindi li ho convertiti in tutto ciò di cui avevo bisogno. È stato specificato un parametro facoltativo con una stringa vuota. Non è la soluzione più pulita, ma ha funzionato. Fai solo attenzione a cogliere tutte le eccezioni che possono verificarsi.


0

Per ogni evenienza, se qualcuno vuole passare un callback (o delegate) come parametro opzionale, può farlo in questo modo.

Parametro callback opzionale:

public static bool IsOnlyOneElement(this IList lst, Action callbackOnTrue = (Action)((null)), Action callbackOnFalse = (Action)((null)))
{
    var isOnlyOne = lst.Count == 1;
    if (isOnlyOne && callbackOnTrue != null) callbackOnTrue();
    if (!isOnlyOne && callbackOnFalse != null) callbackOnFalse();
    return isOnlyOne;
}

0

i parametri opzionali non sono altro che parametri di default! ti suggerisco di fornire entrambi i parametri predefiniti. GetFooBar (int a = 0, int b = 0) se non si dispone di alcun metodo sovraccarico, si otterrà a = 0, b = 0 se non si passa alcun valore, se si passa 1 valore, si otterrà , ha superato il valore per a, 0 e se si superano 2 valori, 1 verrà assegnato a a e 2 a b.

spero che risponda alla tua domanda.


0

Nel caso in cui i valori predefiniti non siano disponibili, il modo per aggiungere un parametro facoltativo è utilizzare la classe .NET OptionalAttribute - https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute ? view = netframework-4.8

L'esempio del codice è di seguito:

namespace OptionalParameterWithOptionalAttribute
{
    class Program
    {
        static void Main(string[] args)
        {
            //Calling the helper method Hello only with required parameters
            Hello("Vardenis", "Pavardenis");
            //Calling the helper method Hello with required and optional parameters
            Hello("Vardenis", "Pavardenis", "Palanga");
        }
        public static void Hello(string firstName, string secondName, 
            [System.Runtime.InteropServices.OptionalAttribute] string  fromCity)
        {
            string result = firstName + " " + secondName;
            if (fromCity != null)
            {
                result += " from " + fromCity;
            }
            Console.WriteLine("Hello " + result);
        }

    }
}

-4

Puoi provare anche questo
Tipo 1
public void YourMethod(int a=0, int b = 0) { //some code }


Tipo 2
public void YourMethod(int? a, int? b) { //some code }

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.