Wie können Sie optionale Parameter in C # verwenden?

493

Hinweis: Diese Frage wurde zu einem Zeitpunkt gestellt, als C # noch keine optionalen Parameter unterstützte (dh vor C # 4).

Wir erstellen eine Web-API, die programmgesteuert aus einer C # -Klasse generiert wird. Die Klasse hat eine Methode GetFooBar(int a, int b)und die API hat eine MethodeGetFooBar die Abfrageparameter wie &a=foo &b=bar.

Die Klassen müssen optionale Parameter unterstützen, die in der Sprache C # nicht unterstützt werden. Was ist der beste Ansatz?

Kalid
quelle
7
Oder warten Sie, bis C # 4.0 freigegeben ist. Optionale Parameter werden unterstützt.
Micah

Antworten:

1055

Überrascht erwähnte niemand optionale C # 4.0-Parameter, die so funktionieren:

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

Bearbeiten: Ich weiß, dass zu dem Zeitpunkt, als die Frage gestellt wurde, C # 4.0 nicht existierte. Aber diese Frage ist immer noch die Nummer 1 in Google für "optionale C # -Argumente", also dachte ich - diese Antwort ist es wert, hier zu sein. Es tut uns leid.

Alex
quelle
58
Zum Zeitpunkt der Frage war C # 4.0 noch nicht vorhanden.
Forrest Marvez
91
Ja, ich habe das übersehen, sorry. Aber diese Frage ist immer noch die Nummer 1 in Google für "C # optionale Argumente" - diese Antwort ist es wert, hier zu sein :)
Alex
45
Gut, dass Sie aktuelle Informationen liefern. Im Idealfall werden die ursprünglichen Antworten mit aktuellen Informationen wie C # 4.0 aktualisiert. Ich glaube, das hatten die SO-Leute ursprünglich im Sinn, eine Wiki-Mentalität, aber jeder hat ein bisschen zu viel Angst, die Antwort eines anderen zu bearbeiten.
Rowan
Etwas Interessantes, das ich bei WebServices entdeckt habe, ist, dass (sicherlich in dem Projekt, das ich teste) alle Bool-Werte in einem Querystring standardmäßig optional sind. Offensichtlich sind sie standardmäßig FALSE.
Carlos P
4
Es ist zu beachten, dass optionale Parameter nach allen nicht optionalen Parametern stehen müssen. dh Sie können keine öffentliche Leere haben SomeMethod (int b = 0, int a)
Andrew Meservy
129

Eine andere Option ist die Verwendung des Schlüsselworts params

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

Genannt wie ...

DoSomething(this, that, theOther);
Tim Jarvis
quelle
57
Diese Antwort erklärt das params-Schlüsselwort wunderschön in 10 Zeilen, MSDN tut es immer noch nicht in 30. +1
User2400
1
Vielen Dank! Dies inspirierte mich, eine einfache (für meinen aktuellen Anwendungsfall) Protokollierungsfunktion zu schreiben: 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(); }Beispielaufruf:log("...Done,",(watch.ElapsedMilliseconds/1000).ToString(),"s");
pfonseca
Könnten Sie erwähnen, unterstützt net 3.5 es? offizielle Dokumente haben das nicht erwähnt.
T.Todua
@ T.Todua - Ich bin nicht 100% sicher, was Sie hier fragen - Dotnet Framework 3.5 enthalten C # v3.0 - Version 3.0 unterstützte das Schlüsselwort params, hatte jedoch keine optionalen Parameter, die in C # v4.0 eingeführt wurden , das in Dotnet Framework 4.0 enthalten war
Tim Jarvis
@ TimJarvis ja, das war es, wonach ich gefragt habe. tnx
T.Todua
77

In C # würde ich normalerweise mehrere Formen der Methode verwenden:

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

UPDATE: Dies war die Art und Weise, wie ich Standardwerte mit C # 2.0 erstellt habe. Die Projekte, an denen ich gerade arbeite, verwenden C # 4.0, das jetzt optionale Parameter direkt unterstützt. Hier ist ein Beispiel, das ich gerade in meinem eigenen Code verwendet habe:

public EDIDocument ApplyEDIEnvelop(EDIVanInfo sender, 
                                   EDIVanInfo receiver, 
                                   EDIDocumentInfo info,
                                   EDIDocumentType type 
                                     = new EDIDocumentType(EDIDocTypes.X12_814),
                                   bool Production = false)
{
   // My code is here
}
stephenbayer
quelle
1
Ich glaube, Sie können Konstruktoren nicht in Standardparametern aufrufen, sie müssen "zur Kompilierungszeit" kompatibel sein, nicht zur "Laufzeit" ... Oder irre ich mich?
Alex
45

Von dieser Seite:

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

C # erlaubt die Verwendung des Attributs [Optional] (von VB, obwohl es in C # nicht funktioniert). Sie können also eine Methode wie diese haben:

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

In unserem API-Wrapper erkennen wir optionale Parameter (ParameterInfo p.IsOptional) und legen einen Standardwert fest. Das Ziel ist es, Parameter als optional zu markieren, ohne auf Kludges zurückzugreifen, wie "optional" im Parameternamen.

Kalid
quelle
4
Aber wie benutzt man dann die Funktion Foo? Foo (1,1); foo (1,1, null) und foo (1,1, Missing.value) werfen alle Ausnahmen
Bolu
2
Seltsam, einige der obigen Antworten sind viel besser als diese.
Maidot
26

Sie könnten Methodenüberladung verwenden ...

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

Es hängt von den Methodensignaturen ab. In dem von mir angegebenen Beispiel fehlt die Methode "int b", da sie dieselbe Signatur wie die Methode "int a" haben würde.

Sie könnten Nullable-Typen verwenden ...

GetFooBar (int? A, int? B)

Sie können dann mit a.HasValue überprüfen, ob ein Parameter festgelegt wurde.

Eine andere Möglichkeit wäre die Verwendung eines Parameters 'params'.

GetFooBar (params object [] args)

Wenn Sie mit benannten Parametern arbeiten möchten, müssten Sie einen Typ erstellen, um diese zu verarbeiten, obwohl ich denke, dass es für Web-Apps bereits so etwas gibt.

Kepboy
quelle
24

Sie können optionale Parameter in C # 4.0 ohne Bedenken verwenden. Wenn wir eine Methode haben wie:

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

Wenn Sie die Methode aufrufen, können Sie folgende Parameter überspringen:

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

C # 4.0 implementiert eine Funktion namens "Named Parameters", Sie können Parameter tatsächlich anhand ihrer Namen übergeben, und natürlich können Sie Parameter in beliebiger Reihenfolge übergeben :)

kristi_io
quelle
20

Hallo optionale Welt

Wenn die Laufzeit einen Standardparameterwert liefern soll, müssen Sie Reflection verwenden, um den Aufruf durchzuführen. Nicht so schön wie die anderen Vorschläge für diese Frage, aber kompatibel mit 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 });
        }
    }
}
Hugh Allen
quelle
16

Eine einfache Möglichkeit, Parameter an einer beliebigen Position wegzulassen , besteht darin, nullbare Typen wie folgt zu nutzen:

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("-");
}

Strings sind bereits nullbare Typen, daher benötigen sie das ? .

Sobald Sie diese Methode haben, sind alle folgenden Aufrufe gültig :

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

Wenn Sie eine Methode auf diese Weise definieren, können Sie nur die gewünschten Parameter festlegen, indem Sie sie benennen . Weitere Informationen zu benannten und optionalen Parametern finden Sie unter folgendem Link:

Benannte und optionale Argumente (C # -Programmierhandbuch) @ MSDN

SteakOverflow
quelle
9

Ich stimme stephenbayer zu. Da es sich jedoch um einen Webservice handelt, ist es für Endbenutzer einfacher, nur eine Form der Webmethode zu verwenden, als mehrere Versionen derselben Methode zu verwenden. Ich denke in dieser Situation sind nullbare Typen perfekt für optionale Parameter.

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
  }  
}
Vivek
quelle
+1 Ratschlag. Machen Sie sich das nicht zur Gewohnheit, da es sehr unordentlich werden kann.
Mhenrixon
7

Optionale Parameter gelten für Methoden. Wenn Sie optionale Argumente für eine Klasse benötigen und Sie sind:

  • Verwenden von c # 4.0: Verwenden Sie optionale Argumente im Konstruktor der Klasse, eine Lösung, die ich bevorzuge, da sie näher an den Methoden liegt und daher leichter zu merken ist. Hier ist ein Beispiel:

    class myClass
    {
        public myClass(int myInt = 1, string myString =
                               "wow, this is cool: i can have a default string")
        {
            // do something here if needed
        }
    }
  • Verwenden von c # -Versionen vor c # 4.0: Sie sollten die Konstruktorkettung verwenden (mit dem Schlüsselwort: this), wobei einfachere Konstruktoren zu einem "Masterkonstruktor" führen. Beispiel:

    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
        }
    }
baskinhu
quelle
3

Die typische Art und Weise, wie dies in C # behandelt wird, besteht darin, die Methode zu überladen. Indem Sie mehrere Versionen der Methode mit unterschiedlichen Parametern erstellen, erstellen Sie effektiv optionale Parameter. In Formularen mit weniger Parametern rufen Sie normalerweise das Formular der Methode auf, wobei alle Parameter Ihre Standardwerte beim Aufruf dieser Methode festlegen.

cfbarbero
quelle
2

Sie können Ihre Methode überladen. Eine Methode enthält einen Parameter GetFooBar(int a)und die andere enthält beide Parameter.GetFooBar(int a, int b)

user2933082
quelle
2

Verwenden von Überladungen oder Verwenden von C # 4.0 oder höher

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

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

quelle
1

Für eine größere Anzahl optionaler Parameter kann ein einzelner Parameter von Dictionary mit der ContainsKey-Methode verwendet werden. Ich mag diesen Ansatz, weil ich damit eine Liste oder ein T einzeln übergeben kann, ohne eine ganz andere Methode erstellen zu müssen (schön, wenn beispielsweise Parameter als Filter verwendet werden sollen).

Beispiel (neues Dictionary <string, Object> () würde übergeben, wenn keine optionalen Parameter gewünscht werden):

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

Erstellen Sie anstelle von Standardparametern einfach eine Wörterbuchklasse aus dem übergebenen Querystring. Eine Implementierung, die fast identisch mit der Arbeitsweise von asp.net-Formularen mit Querystrings ist.

dh Request.QueryString ["a"]

Dadurch wird die Blattklasse vom Werks- / Boilerplate-Code entkoppelt.


Möglicherweise möchten Sie auch Webdienste mit ASP.NET auschecken . Webdienste sind eine Web-API, die automatisch über Attribute in C # -Klassen generiert wird.

Robert Paulson
quelle
0

Ein bisschen zu spät zur Party, aber ich suchte nach der Antwort auf diese Frage und fand schließlich einen weiteren Weg, dies zu tun. Deklarieren Sie die Datentypen für die optionalen Argumente Ihrer Webmethode als Typ XmlNode. Wenn das optionale Argument weggelassen wird, wird dieses auf null gesetzt. Wenn es vorhanden ist, können Sie den Zeichenfolgenwert durch Aufrufen von arg.Value, dh, erhalten.

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

Was an diesem Ansatz auch anständig ist, ist, dass die von .NET generierte Homepage für das ws immer noch die Argumentliste anzeigt (obwohl Sie die praktischen Texteingabefelder zum Testen verlieren).

Ron K.
quelle
3
Ist das besser als die Verwendung von nullbaren Typen?
Kirk Broadhurst
0

Ich muss einen Webdienst schreiben, der 7 Parameter akzeptiert. Jedes ist ein optionales Abfrageattribut für eine SQL-Anweisung, die von diesem Webdienst umschlossen wird. Es kommen also zwei Problemumgehungen für nicht optionale Parameter in den Sinn ... beide ziemlich schlecht:

Methode 1 (Parameter 1, Parameter 2, Parameter 3, Parameter 4, Parameter 5, Parameter 6, Parameter 7) Methode 1 (Parameter 1, Parameter 2, Parameter 3, Parameter 4, Parameter 5, Parameter 6) Methode 1 (Parameter 1, Parameter 2, Parameter 3, Parameter 4, Parameter 5, Parameter 7) ) ... beginne das Bild zu sehen. Auf diese Weise liegt der Wahnsinn. Viel zu viele Kombinationen.

Nun zu einer einfacheren Methode, die umständlich aussieht, aber funktionieren sollte: Methode1 (param1, bool useParam1, param2, bool useParam2 usw.)

Das ist ein Methodenaufruf, Werte für alle Parameter sind erforderlich und es wird jeder Fall darin behandelt. Es ist auch klar, wie man es über die Benutzeroberfläche verwendet.

Es ist ein Hack, aber es wird funktionieren.

Spanky
quelle
2
Aus diesem Grund existieren nullfähige Parameter.
Kirk Broadhurst
0

Ich musste dies in einem VB.Net 2.0-Webdienst tun. Am Ende habe ich die Parameter als Zeichenfolgen angegeben und sie dann in das konvertiert, was ich brauchte. Ein optionaler Parameter wurde mit einer leeren Zeichenfolge angegeben. Nicht die sauberste Lösung, aber es hat funktioniert. Achten Sie nur darauf, dass Sie alle Ausnahmen abfangen, die auftreten können.

Matt
quelle
0

Nur für den Fall, dass jemand einen Rückruf (oder delegate) als optionalen Parameter übergeben möchte, kann dies auf diese Weise geschehen .

Optionaler Rückrufparameter:

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;
}
CodeArtist
quelle
0

Optionale Parameter sind nichts anderes als Standardparameter! Ich schlage vor, Sie geben beide Standardparameter. GetFooBar (int a = 0, int b = 0), wenn Sie keine überladene Methode haben, führt zu a = 0, b = 0, wenn Sie keine Werte übergeben, wenn Sie 1 Wert übergeben, führt zu , übergebener Wert für a, 0 und wenn Sie 2 Werte übergeben, wird der erste Wert a und der zweite Wert b zugewiesen.

hoffe das beantwortet deine frage.

user3555836
quelle
0

Wenn keine Standardwerte verfügbar sind, können Sie einen optionalen Parameter hinzufügen, indem Sie die .NET OptionalAttribute-Klasse verwenden - https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute view = netframework-4.8

Beispiel für den Code ist unten:

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

    }
}
Sharunas Bielskis
quelle
-4

Sie können dies auch versuchen
Typ 1
public void YourMethod(int a=0, int b = 0) { //some code }


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

Ankit Panwar
quelle