Hallo zusammen,
ich arbeite mich gerade etwas bei den Grundlagen ein und habe da mal eine Frage.
Felder einer Klasse sollte man ja kapseln, Etwa so:
public class Circle
{
private int _Radius;
public int Radius
{
get { return _Radius; }
set
{
if (value >= 0)
_Radius = value;
else
Console.WriteLine("Ungültig.");
}
}
}
Damit habe ich ja ein außerhalb der Klasse sichtbares Feld und ein nicht sichtbares (_Radius).
Wie stellt sich das aber dar, wenn ich das kompakter (Auto-Property) schreibe (und auf die Prüfung verzichte):
public class Circle
{
public int Radius {get; set;)
}
Wird hier implizit auch ein privates Feld angelegt? Wie heißt das?
Danke und Grüße
Sven
Google und Stackoverflow sind dein Freund…
… is-it-possible-to-access-backing-fields-behind-auto-implemented-properties
Hallo sven007,
die Auto-Properties sind eine Erleichterung seitens C#, welche das Tippen vom klassichen Muster für Eigenschaften vereinfacht.
Aus
public class Person
{
private string _name; // das ist ein Feld -- lt. Namenskonvention klein geschrieben und oft mit einem _ vorangestellt
// Eigenschaft klassisch geschrieben
public string Name
{
get { return _name; }
set { _name = value; }
}
// Eigenschaft mit expression bodyed members geschrieben, ist im kompilierten Code gleich der oberen Eigenschaft (außer der Name der Eigenschaft ist anders)
public string Name1
{
get => _name;
set => _name = value;
}
}
Da dies mühsam zum Tippen werden kann, wurden mit C# 3.0 die "Auto-Properties" eingeführt:
public class Person
{
public string Name { get; set; }
}
Dabei erzeugt der C# Compiler das "Backing-Field" automatisch. Dieser Vorteil der weniger Tipp-Arbeit hat aber den Nachteil, dass keine Validierungen, etc. im Setter der Eigenschaft durchgeführt werden können. D.h. willst du im Kreisbeispiel den Radius prüfen, so verzichte auf Auto-Properties und schreib sie manuell wie du es gemacht hast.
Nebenbemerkung: da solche Klassen wie oben gezeigt recht häufig sind und als POCO bezeichnet werden, wurde mit die C# 9 die Möglichkeit von Records geschaffen, mit denen sich das noch einfacher schreiben lässt:
public record Person(string Name);
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Moin Gü,
danke für die Rückmeldung.
Da dies mühsam zum Tippen werden kann, wurden mit C# 3.0 die "Auto-Properties" eingeführt:
Das ist mir Bewusst. Gehen wir aber mal davon aus, dass ich keine Wertüberprüfung, aber schon eine Kapselung möchte. Bei Deinem Beispiel gibt es dann das eine öffentliche Feld Name. Meine Frage war, ob es dadurch auch implizit ein privates Feld (bspw. _Name) gibt, welches ich in der Klasse verwenden kann. Dem ist nicht so, oder?
Also ganz doof gefragt: Welchen Vorteil hat
public string Name { get; set; }
gegenüber
public string Name;
In beiden fällen kann ich doch von außen lesend und schreibend auf Name zugreifen.
Grüße
Sven
Das ist mir Bewusst. Gehen wir aber mal davon aus, dass ich keine Wertüberprüfung, aber schon eine Kapselung möchte. Bei Deinem Beispiel gibt es dann das eine öffentliche Feld Name. Meine Frage war, ob es dadurch auch implizit ein privates Feld (bspw. _Name) gibt, welches ich in der Klasse verwenden kann. Dem ist nicht so, oder?
Steht im Stackoverflow-Link oben, offensichtlich hast ihn nicht gelesen.
Also ganz doof gefragt: Welchen Vorteil hat
public string Name { get; set; }
gegenüber
public string Name;
In beiden fällen kann ich doch von außen lesend und schreibend auf Name zugreifen.
Grüße
Sven
Versuch mal Databinding mit dem Feld zu benutzen.
In beiden fällen kann ich doch von außen lesend und schreibend auf Name zugreifen.
Das eine sind Felder, das andere sind Eigenschaften.
Sehen aus Dev-sicht ähnlich aus; funktionieren aber vollkommen verschiedenen und haben anderen Aufgaben.
Nur in der einfachsten Verwendung, als "dummer" Datenspeicher einer Klassen, funktionieren sie gleich (Dein Beispiel).
In der .NET Welt: riesen Unterschiede.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Danke.
Und das hier ist nur eine andere Schreibweise?
public string Name
{
get => _name;
set => _name = value;
}
Das ist eine explizite Implementierung mit einem Backing Field.
Das, was Dir gfoidl oben schon ausführlich erklärt hat und Dir Jompikumpi verlinkt hat.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hallo sven007,
In beiden fällen kann ich doch von außen lesend und schreibend auf Name zugreifen.
Noch als Ergänzung zu den anderen Antworten dazu.
Stell dir vor du erstellst eine Library und diese hat eine öffentliche API. Diese Library sollte nach Semantic Versioning 2.0.0 versioniert werden.
Jetzt hast du nur ein Feld
public class Person
{
public string Name;
}
und kommst später drauf, dass doch eine Validierung nötig wäre beim Setzen des Wertes (für das Feld). Das geht dann nicht elegant, daher wird jetzt aus dem Feld eine Eigenschaft gemacht um dort validieren zu können:
public class Person
{
private string _name;
public string Name
{
get => _name;
set
{
if (value is null)
{
throw new ArgumentNullException("....");
}
_name = value;
}
}
}
Aber: das Ändern von Feld zu Eigenschaft ist eine "breaking change", da sie das öffentliche API verändert! Gem. SemVer müsste somit eine neue Hauptversion erstellt werden.
Werden also gleich Properties / Eigenschaften verwendet, so gewinnt man Flexibilität und kann später einfacher die Implementierung der Eigenschaft ändern.
Felder hingegen sollte so gut wie immer private sein (Datenkapselung).
ob es dadurch auch implizit ein privates Feld (bspw. _Name) gibt, welches ich in der Klasse verwenden kann. Dem ist nicht so, oder?
Der C# Compiler erzeugt folgenden Code. Dort ist das <Name>k__BackingField
zu sehen, aber das ist vom "Benutzercode" nicht direkt zugreifbar (und via Reflection sollte auch nicht darauf zugegriffen werden, da der Name des Feldes sich mit jeder C# Compiler-Version ändern kann / darf und somit dieser Code sehr fragil wäre).
Wie FZelle erwähnte kommt mit C# 10 das field
Schlüsselwort, damit sollte
public class Person
{
public string Name { get; set => field = value ?? throw new ArgumentNullException(); }
}
möglich werden.
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"