Start Debugging

C# 14: Das field-Schlüsselwort und Eigenschaften mit field-basierter Speicherung

C# 14 führt das kontextuelle Schlüsselwort field für Eigenschafts-Accessoren ein. So können Sie zu Auto-Properties benutzerdefinierte Logik hinzufügen, ohne ein separates Hintergrundfeld zu deklarieren.

C# 14 führt ein neues kontextuelles Schlüsselwort ein, field, das innerhalb der Accessoren einer Eigenschaft (den Blöcken get, set oder init) verwendet werden kann, um auf die zugrunde liegende Speicherung der Eigenschaft zu verweisen. Einfach gesagt ist field ein Platzhalter, der die verborgene Variable repräsentiert, in der der Wert einer Eigenschaft gespeichert wird. Mit diesem Schlüsselwort können Sie automatisch implementierten Eigenschaften benutzerdefinierte Logik hinzufügen, ohne manuell ein separates privates Feld zu deklarieren. Es war erstmals als Vorschau in C# 13 verfügbar (mit .NET 9 und der Sprachversion auf Preview gesetzt) und ist offiziell Teil der Sprache in C# 14.

Warum ist das nützlich? Wollten Sie vor C# 14 Logik (etwa Validierung oder Änderungs-Benachrichtigung) zu einer Eigenschaft hinzufügen, mussten Sie sie zu einer vollständigen Eigenschaft mit privatem Hintergrundfeld machen. Das bedeutete mehr Boilerplate-Code und das Risiko, dass andere Klassenmitglieder versehentlich direkt auf das Feld zugreifen und so die Eigenschaftslogik umgehen. Das neue field-Schlüsselwort löst diese Probleme, indem der Compiler das Hintergrundfeld für Sie erzeugt und verwaltet, während Sie in Ihrem Eigenschaftscode einfach field verwenden. Das Ergebnis sind klarere, wartungsfreundlichere Eigenschaftsdeklarationen, und das Hintergrundspeicher leakt nicht in den restlichen Gültigkeitsbereich Ihrer Klasse.

Vorteile und Anwendungsfälle von field

Das Schlüsselwort field wurde eingeführt, um Eigenschaftsdeklarationen prägnanter und weniger fehleranfällig zu machen. Hier die wichtigsten Vorteile und Szenarien, in denen es nützlich ist:

Insgesamt verbessert field die Lesbarkeit und Wartbarkeit, indem redundanter Code wegfällt und der Fokus nur auf dem benötigten benutzerdefinierten Verhalten liegt. Konzeptionell ist es vergleichbar mit der Funktionsweise des Schlüsselworts value in einem Setter (das den zugewiesenen Wert repräsentiert); hier steht field für die zugrunde liegende Speicherung der Eigenschaft.

Vorher vs. nachher: manuelles Hintergrundfeld vs. field-Schlüsselwort

Um den Unterschied zu sehen, vergleichen wir, wie Sie eine Eigenschaft, die eine Regel erzwingt, vor C# 14 deklariert hätten und nach der Einführung des neuen field-Schlüsselworts.

Szenario: Angenommen, wir wollen eine Eigenschaft Hours, die niemals auf eine negative Zahl gesetzt werden darf. In älteren C#-Versionen hätten wir Folgendes geschrieben:

Vor C# 14, mit manuellem Hintergrundfeld:

public class TimePeriodBefore
{
    private double _hours;  // backing field

    public double Hours
    {
        get { return _hours; }
        set 
        {
            if (value < 0)
                throw new ArgumentOutOfRangeException(nameof(value), "Value must not be negative");
            _hours = value;
        }
    }
}

In diesem Code vor C# 14 mussten wir ein privates Feld _hours einführen, um den Wert zu speichern. Der Getter der Eigenschaft gibt dieses Feld zurück, und der Setter führt eine Prüfung durch, bevor er _hours zuweist. Das funktioniert, ist aber wortreich: Wir haben zusätzlichen Code, um _hours zu deklarieren und zu verwalten, und _hours ist überall in der Klasse zugänglich (das heißt, andere Methoden könnten in _hours schreiben und die Validierungslogik umgehen, wenn man nicht aufpasst).

Ab C# 14, mit dem field-Schlüsselwort:

public class TimePeriod
{
    public double Hours
    {
        get;  // auto-implemented getter (compiler provides it)
        set => field = (value >= 0) 
            ? value 
            : throw new ArgumentOutOfRangeException(nameof(value), "Value must not be negative");
    }
}

Hier ist die Eigenschaft Hours ohne explizites Hintergrundfeld deklariert. Wir verwenden get; ohne Body, was auf einen automatischen Getter hinweist, und stellen einen Body für set bereit, der field nutzt. Der Ausdruck field = ... im Setter weist den Compiler an, dem Hintergrundfeld der Eigenschaft etwas zuzuweisen. Der Compiler erzeugt im Hintergrund automatisch ein privates Feld und implementiert den get-Accessor so, dass er dieses Feld zurückgibt. Im obigen Setter werfen wir bei negativem value eine Ausnahme; andernfalls weisen wir field zu (das den Wert speichert). Wir mussten _hours nicht selbst deklarieren, und der Body des Getters muss auch nicht geschrieben werden; das übernimmt der Compiler. Das Ergebnis ist eine prägnantere Eigenschaftsdefinition mit demselben Verhalten.

Beachten Sie, wie viel klarer die C#-14-Variante ist:

Sie können field bei Bedarf auch in einem get-Accessor verwenden. Um beispielsweise eine Lazy-Initialisierung zu implementieren, könnten Sie etwa Folgendes schreiben:

public string Name 
{
    get => field ??= "Unknown";
    set => field = value;
}

In diesem Fall weist der Getter beim ersten Zugriff auf Name, falls noch nicht gesetzt, dem Hintergrundfeld einen Standardwert "Unknown" zu und gibt ihn zurück. Folgende Lese- oder Schreibzugriffe nutzen dasselbe field. Ohne dieses Feature hätten Sie ein privates Feld und mehr Code im Getter gebraucht, um dasselbe Verhalten zu erreichen.

Wie behandelt der Compiler das field-Schlüsselwort?

Wenn Sie field in einem Eigenschafts-Accessor verwenden, erzeugt der Compiler im Hintergrund ein verborgenes Hintergrundfeld für diese Eigenschaft (sehr ähnlich wie bei einer automatisch implementierten Eigenschaft). Dieses Feld sehen Sie in Ihrem Quellcode nie, der Compiler vergibt aber einen internen Namen (z. B. so etwas wie <Hours>k__BackingField) und nutzt es, um den Wert der Eigenschaft zu speichern. Folgendes passiert unter der Haube:

TLDR: Der Compiler erzeugt ein privates Hintergrundfeld und verdrahtet Ihre Eigenschafts-Accessoren so, dass sie es verwenden. Sie erhalten die Funktionalität einer vollständigen Eigenschaft mit nur einem Bruchteil des Codes. Implementierungstechnisch bleibt die Eigenschaft eine echte automatische Eigenschaft; Sie haben nur einen Hook erhalten, um Logik einzuhängen.

Syntax- und Verwendungsregeln für field

Beim Einsatz des field-Schlüsselworts beachten Sie folgende Regeln und Einschränkungen:

Kurz gesagt: Verwenden Sie field innerhalb Ihrer Eigenschafts-Accessoren, um auf den verborgenen Speicher dieser Eigenschaft zu verweisen, und sonst nirgends. Für alles außerhalb von Eigenschaften gelten die normalen C#-Sichtbarkeitsregeln.

Umgang mit Namenskonflikten (wenn Sie eine eigene field-Variable haben)

Da field in älteren C#-Versionen kein reserviertes Wort war, ist es möglich (wenn auch ungewöhnlich), dass etwas Code “field” als Variablen- oder Feldnamen verwendet hat. Mit der Einführung des kontextuellen Schlüsselworts field in Accessoren könnte solcher Code mehrdeutig werden oder brechen. Das Sprachdesign berücksichtigt das:

private int field = 10; // a field unfortunately named "field" 
public int Example
{
    get { return @field; } // use @field to return the actual field 
    set { @field = value; } // or this.field = value; either works 
}

Referenzen

  1. field – Field backed property declarations
  2. C# Feature Proposal Notes – field keyword in properties”
  3. What’s new in C# 14

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Zurück