Menu

C# optionale Parameter und benannte Argumente: Standardwerte und Regeln

Wie optionale Parameter und benannte Argumente in C# funktionieren: Standardwerte und die Regel der Konstante zur Kompilierzeit, Reihenfolge der Parameter, Argumente per Namen überspringen, optionale Parameter gegenüber Überladungen, Caller-Info-Attribute und die Versionsfalle von Standardwerten, die in den Aufrufer kompiliert werden.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Ein optionaler Parameter hat in der Methodendeklaration einen Standardwert, Aufrufer dürfen ihn also weglassen. Ein benanntes Argument übergibt einen Wert über den Parameternamen statt über die Position. Zusammen lassen sie eine Methode viele Aufrufformen bedienen, ohne einen Stapel Überladungen.

Ausgabe:

to ana@mail.com: (no subject), retries 3
to ben@mail.com: Invoice #1042, retries 3
to cy@mail.com: (no subject) [URGENT], retries 3
to dev@mail.com: Build failed, retries 0

Der dritte Aufruf überspringt subject und setzt urgent per Namen; ohne benannte Argumente müsste er erneut "(no subject)" übergeben, nur um die dritte Position zu erreichen. Der letzte Aufruf übergibt jedes Argument per Namen in einer anderen Reihenfolge als in der Deklaration, was erlaubt ist.

Regeln für Standardwerte

Ein Standardwert muss etwas sein, das der Compiler berechnen kann:

  • eine Konstante (3, "INFO", true, 1.5m, ein const-Feld, ein Enum-Member)
  • null für einen Referenz- oder Nullable-Typ
  • default(T) oder new T() für einen Werttyp T

Alles, was zur Laufzeit ausgewertet wird, wird abgelehnt. Der klassische Fall ist ein Datum:

static void Schedule(string task, DateTime at = DateTime.Now) { }
// error CS1736: Default parameter value for 'at' must be a compile-time constant

Der übliche Ausweg ist ein Nullable-Parameter mit null als Standardwert, der im Rumpf aufgelöst wird:

Ausgabe:

backup at 2026-01-01 09:00, tags: 0
report at 2026-03-15 18:30, tags: 0
deploy at 2026-01-01 09:00, tags: 2

Derselbe Trick hilft bei Collections: Ein Standardwert new List<string>() ist keine Konstante, nimm also null als Standard und erzeuge die Liste im Rumpf. Das vermeidet auch den aus Python bekannten Bug mit einem geteilten, veränderlichen Standardwert, den C# ausschließt, weil nur Konstanten erlaubt sind.

Regeln zur Reihenfolge

Pflichtparameter kommen zuerst, optionale danach und ein params-Array (falls vorhanden) zuletzt:

static void Log(string message, string level = "INFO", params string[] tags) { }   // OK

static void Log(string level = "INFO", string message) { }
// error CS1737: Optional parameters must appear after all required parameters

ref- und out-Parameter können nicht optional sein.

Auf der Aufruferseite füllen positionelle Argumente die Parameter von vorn. Benannte Argumente können ihnen in beliebiger Reihenfolge folgen. Seit C# 7.2 darf ein benanntes Argument auch vor einem positionellen stehen, aber nur, wenn es an seiner eigenen Position steht (SendEmail("a@b.c", subject: "Hi", true)); in älteren Versionen müssen alle benannten Argumente am Ende stehen. Einen Pflichtparameter wegzulassen ist ein Kompilierfehler, auch wenn andere benannt werden.

Benannte Argumente für bessere Lesbarkeit

Benannte Argumente sind nützlich, selbst wenn nichts optional ist. Wörtliche true, false, null und nackte Zahlen sagen an der Aufrufstelle nichts aus:

ResizeImage(photo, 800, 600, true, false);                                   // which is which?
ResizeImage(photo, width: 800, height: 600, keepAspect: true, upscale: false);

Einen Parameter umzubenennen wird damit zu einer Breaking Change für Aufrufer, die den Namen verwenden, was man in einer öffentlichen Bibliothek im Kopf behalten sollte.

Optionale Parameter gegenüber Überladungen

Vor C# 4 brauchte dieselbe Flexibilität eine Überladung pro Kombination. Optionale Parameter fassen sie in einer Methode zusammen:

// overloads
static void Connect(string host) => Connect(host, 443);
static void Connect(string host, int port) => Connect(host, port, 30);
static void Connect(string host, int port, int timeoutSeconds) { /* ... */ }

// one method with optional parameters
static void Connect(string host, int port = 443, int timeoutSeconds = 30) { /* ... */ }

Existiert beides, bevorzugt die Überladungsauflösung einen Kandidaten, bei dem kein Standardwert eingesetzt werden muss:

Ausgabe:

Greet()
Greet(string) with Lena

Greet() passt auf beide Methoden, und der Compiler wählt die ohne weggelassenen optionalen Parameter. Beide Techniken für denselben Namen zu mischen erzeugt vor allem Aufrufe, deren Ziel schwer vorherzusagen ist, entscheide dich also pro Methode für eine.

Nimm Überladungen, wenn die Varianten anderen Code oder andere Parametertypen brauchen, und optionale Parameter, wenn sie sich nur in Standardwerten unterscheiden.

Standardwerte werden in den Aufrufer kompiliert

Ein Standardwert wird nicht zur Laufzeit nachgeschlagen. Der Compiler kopiert ihn in jede Aufrufstelle, wenn der aufrufende Code kompiliert wird. Connect("api.shop.com") wird zu Connect("api.shop.com", 443, 30) kompiliert.

Das hat Folgen für Bibliotheken. Angenommen, Version 1 eines Pakets liefert Connect(string host, int timeoutSeconds = 30), und Version 2 ändert den Standardwert auf 10. Eine gegen Version 1 kompilierte Anwendung übergibt weiterhin 30, nachdem du die DLL der Version 2 eingesetzt hast, bis die Anwendung selbst neu kompiliert wird. Einer bestehenden öffentlichen Methode einen neuen optionalen Parameter hinzuzufügen bricht ebenfalls bereits kompilierte Aufrufer, weil sich die Signatur der Methode geändert hat und sie noch die alte suchen (eine MissingMethodException zur Laufzeit).

Innerhalb einer Anwendung, die als Ganzes kompiliert wird, spielt das nie eine Rolle. Bei öffentlichen APIs in NuGet-Paketen vermeiden Überladungen (die die Standardwerte in der Bibliothek halten) oder ein im Rumpf aufgelöster Standardwert null das Problem.

Standardwerte und der deklarierte Typ

Dieselbe Regel zur Kompilierzeit bedeutet: Wenn ein Interface und eine Klasse beide Standardwerte deklarieren, kommt der Standardwert vom Typ der Variable, über die du aufrufst, nicht vom Objekt:

Ausgabe:

printing "report" x5
printing "report" x1

Dasselbe Objekt, zwei verschiedene Standardwerte. Halte Standardwerte zwischen einem Interface und seinen Implementierungen identisch oder deklariere sie nur an einer Stelle.

Caller-Info-Attribute

Optionale Parameter stecken auch hinter den Caller-Info-Attributen in System.Runtime.CompilerServices. Der Compiler füllt sie mit Details der Aufrufstelle:

Ausgabe:

[Main:18] starting
[SaveOrder:13] order saved

So halten Logging-Bibliotheken fest, woher eine Meldung kam, ohne dass der Aufrufer es tippen muss, und so bekommen Implementierungen von INotifyPropertyChanged den Namen der Property. [CallerFilePath] ergänzt auf dieselbe Weise den Pfad der Quelldatei.

Häufig gestellte Fragen

Wie mache ich in C# einen Parameter optional?

Gib ihm in der Deklaration einen Standardwert: static void Log(string message, string level = "INFO"). Aufrufer können dann Log("started") oder Log("failed", "ERROR") schreiben. Optionale Parameter müssen nach allen Pflichtparametern stehen, und der Standardwert muss eine Konstante zur Kompilierzeit sein.

Was sind benannte Argumente in C#?

Argumente, die mit dem Parameternamen übergeben werden: SendEmail(to: "ana@mail.com", urgent: true). Damit überspringst du optionale Parameter in der Mitte, übergibst Argumente in beliebiger Reihenfolge und machst Aufrufe mit wörtlichem true/false oder Zahlen auf einen Blick lesbar.

Warum kann ich DateTime.Now nicht als Standardwert eines Parameters verwenden?

Standardwerte müssen Konstanten zur Kompilierzeit sein, und DateTime.Now wird zur Laufzeit berechnet, daher meldet der Compiler CS1736, Default parameter value for 'at' must be a compile-time constant. Nimm stattdessen einen Nullable-Parameter: DateTime? at = null, dann DateTime time = at ?? DateTime.Now; im Rumpf.

Soll ich in C# optionale Parameter oder Methodenüberladungen verwenden?

Optionale Parameter sind einfacher, wenn sich die Varianten nur in Standardwerten unterscheiden. Überladungen sind besser, wenn Varianten andere Logik oder Typen brauchen, und in öffentlichen Bibliotheken, weil ein Standardwert in jeden Aufrufer kompiliert wird und eine spätere Änderung bereits kompilierten Code nicht erreicht.

Was bedeutet „Optional parameters must appear after all required parameters“?

Fehler CS1737: Auf einen Parameter mit Standardwert folgt einer ohne. Setze die Pflichtparameter nach vorn: (string to, bool urgent = false), nicht (bool urgent = false, string to). Nach einem optionalen Parameter dürfen nur weitere optionale Parameter oder ein params-Array folgen.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S