Laden...

Implizit privates Feld bei Auto-Property?

Erstellt von sven007 vor 2 Jahren Letzter Beitrag vor 2 Jahren 327 Views
S
sven007 Themenstarter:in
12 Beiträge seit 2021
vor 2 Jahren
Implizit privates Feld bei Auto-Property?

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

J
61 Beiträge seit 2020
vor 2 Jahren

Google und Stackoverflow sind dein Freund…

is-it-possible-to-access-backing-fields-behind-auto-implemented-properties

6.911 Beiträge seit 2009
vor 2 Jahren

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!"

F
10.010 Beiträge seit 2004
vor 2 Jahren

In C# 10 kommt aber das field keyword hinzu.

S
sven007 Themenstarter:in
12 Beiträge seit 2021
vor 2 Jahren

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

J
61 Beiträge seit 2020
vor 2 Jahren

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.

16.807 Beiträge seit 2008
vor 2 Jahren

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.

S
sven007 Themenstarter:in
12 Beiträge seit 2021
vor 2 Jahren

Danke.
Und das hier ist nur eine andere Schreibweise?


 public string Name
   {
      get => _name;
      set => _name = value;
   }

16.807 Beiträge seit 2008
vor 2 Jahren

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.

6.911 Beiträge seit 2009
vor 2 Jahren

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!"