Öffentliche Felder versus automatische Eigenschaften

353

Uns wird oft gesagt, wir sollten die Kapselung schützen, indem wir Getter- und Setter-Methoden (Eigenschaften in C #) für Klassenfelder erstellen, anstatt die Felder der Außenwelt auszusetzen.

Es gibt jedoch viele Fälle, in denen ein Feld nur dazu dient, einen Wert zu speichern, und für dessen Abruf oder Festlegung keine Berechnung erforderlich ist. Für diese würden wir alle diese Nummer machen:

public class Book
{
    private string _title;

    public string Title
    {
          get{ return _title;  }
          set{ _title = value; }
    }
}

Nun, ich habe ein Geständnis, ich konnte es nicht ertragen, all das zu schreiben (wirklich, es musste nicht geschrieben werden, es musste angeschaut werden), also wurde ich Schurke und benutzte öffentliche Felder.

Dann kommt C # 3.0 und ich sehe, dass sie automatische Eigenschaften hinzugefügt haben:

public class Book
{
    public string Title {get; set;} 
}

Was ist aufgeräumter und ich bin dankbar dafür, aber was ist wirklich so anders, als nur ein öffentliches Feld zu schaffen?

public class Book
{
    public string Title;
}
IJ Kennedy
quelle
6
Ich habe ein Feld in ein Grundstück umgewandelt, damit ich einen Haltepunkt für den Setter festlegen kann
Ian Ringrose
1
Ich tendiere dazu, alles, was nicht privat ist, zu einer Immobilie zu machen, weil die Erkenntnis, dass ich ein Feld in eine Immobilie umgestalten muss, zu unnötigen Kopfschmerzen geführt hat. Eigenschaften, Felder und Methoden. Oh mein! ruft eine Inkompatibilität hervor, die mich in der Vergangenheit gebissen hat.
Steven Wexler
2
Mit dem propCode-Snippet können Sie schnell Eigenschaften erstellen. Geben Sie einfach die propRegisterkarte ein.
Tono Nam

Antworten:

175

In einer verwandten Frage, die ich vor einiger Zeit hatte, gab es einen Link zu einem Beitrag in Jeffs Blog, der einige Unterschiede erklärte.

Eigenschaften vs. öffentliche Variablen

  • Die Reflexion funktioniert bei Variablen im Vergleich zu Eigenschaften unterschiedlich. Wenn Sie sich also auf die Reflexion verlassen, ist es einfacher, alle Eigenschaften zu verwenden.
  • Sie können keine Datenbindung für eine Variable vornehmen.
  • Das Ändern einer Variablen in eine Eigenschaft ist eine wichtige Änderung. Zum Beispiel:

    TryGetTitle(out book.Title); // requires a variable
Michael Stum
quelle
24
"Das Ändern einer Variablen in eine Eigenschaft ist eine wichtige Änderung." Dies gilt natürlich nur beim Schreiben einer wiederverwendbaren Bibliothek, was die meisten Entwickler nicht tun.
Steven
30
Eigenschaften, auch automatische Eigenschaften, können virtuell sein, Felder jedoch nicht. Eine Basisklasse kann also eine einfache Backing-Field-Implementierung haben, wie sie vom Compiler für eine Auto-Prop erstellt wurde, während abgeleitete Klassen zusätzliche Validierungen oder andere Logik / Berechnungen durchführen können.
KeithS
28
Ein Feld ist auch eine Variable und kann als Referenz ( refoder outSchlüsselwort) übergeben werden, während eine Eigenschaft ein Zugriffspaarpaar ist und nicht als Referenz übergeben werden kann. Zum Beispiel, bool success = TryGetMyTitle(out myBook.Title);welche Verwendungen outmit einem Feld und nicht mit einer Eigenschaft funktionieren. Dies ist ein klares Beispiel dafür, warum der Wechsel von Feld zu Eigenschaft eine bahnbrechende Veränderung ist!
Jeppe Stig Nielsen
2
@KyleBaran Nein, es macht nicht viel Sinn, da eine Eigenschaft ein Paar von Zugriffsmethoden ist, keine Variable. Normalerweise deklarieren Sie eine lokale Variable (lesen Sie möglicherweise die Eigenschaft und geben Sie ihren Wert in die lokale Variable ein), übergeben Sie die lokale Variable als ref/ outund setzen Sie die Eigenschaft auf den Wert, den die lokale Variable dann hat. Die aufgerufene Methode greift jedoch nicht selbst auf die Eigenschaft zu, sondern auf die lokale Variable, die Sie dort erstellt haben.
Jeppe Stig Nielsen
5
@theberserker True, obwohl Sie in C # 6 public int Foo { get; }eine automatische Eigenschaft mit einem schreibgeschützten Hintergrundfeld erstellen können.
Michael Stum
83

Wenn ich die API-Probleme ignoriere, finde ich das Debuggen am wertvollsten an der Verwendung einer Eigenschaft.

Der CLR-Debugger unterstützt keine Datenunterbrechungspunkte (die meisten nativen Debugger tun dies). Daher ist es nicht möglich, einen Haltepunkt beim Lesen oder Schreiben eines bestimmten Felds in einer Klasse festzulegen. Dies ist in bestimmten Debugging-Szenarien sehr einschränkend.

Da Eigenschaften als sehr dünne Methoden implementiert werden, ist es möglich, Haltepunkte beim Lesen und Schreiben ihrer Werte festzulegen. Dies gibt ihnen ein großes Bein über Felder.

JaredPar
quelle
2
Zehn Jahre später sind Daten-Haltepunkte hier, zumindest für .NET Core :)
Luaan
72

Der Wechsel von einem Feld zu einer Eigenschaft bricht den Vertrag (z. B. muss der gesamte Referenzcode neu kompiliert werden). Wenn Sie also einen Interaktionspunkt mit anderen Klassen haben - einem öffentlichen (und allgemein geschützten) Mitglied - möchten Sie zukünftiges Wachstum planen. Verwenden Sie dazu immer Eigenschaften.

Es ist nichts, was es heute zu einer Auto-Eigenschaft macht, und 3 Monate später wird klar, dass Sie es faul laden möchten, und einen Null-Check in den Getter setzen. Wenn Sie ein Feld verwendet haben, ist dies im besten Fall eine Neukompilierungsänderung und im schlimmsten Fall unmöglich, je nachdem, wer und was sonst noch von Ihren Baugruppen abhängt.

Rex M.
quelle
9
Diese Antwort hat mir gefallen, weil sie nicht die Wörter "Reflection", "Interface" oder "Override" verwendet. (
65

Nur weil es niemand erwähnt hat: Sie können keine Felder auf Schnittstellen definieren. Wenn Sie also eine bestimmte Schnittstelle implementieren müssen, die Eigenschaften definiert, sind Auto-Eigenschaften manchmal eine wirklich nette Funktion.

MartinStettner
quelle
1
Ich würde sagen, wenn Sie eine Schnittstelle benötigen, die Eigenschaften definiert, sollte es sich um eine abstrakte Klasse handeln. Nur weil Sie mit c # Eigenschaften in Schnittstellen definieren können, heißt das nicht, dass Sie sie verwenden sollten. Es ist schlechtes Design.
Odys
8
@odyodyodys - Ich bin nicht sicher, ob ich damit einverstanden bin, dass dies schlechtes Design ist. Bitte erläutern Sie Ihre Gründe?
Zaid Masud
4
@odyodyodys Ich stimme zooone9243 zu: Imp, aus gestalterischer Sicht gibt es keinen Unterschied zwischen der Deklaration einer Eigenschaft und der Deklaration eines Getter / Setter-Paares (was für Schnittstellen üblich ist).
MartinStettner
22
@ zooone9243, + MartinStettner: Das war vor 6 Monaten, ich habe seitdem viel gelernt. Ich nehme es zurück :)
Odys
47

Ein großer Unterschied, der oft übersehen wird und in keiner anderen Antwort erwähnt wird: Überschreiben . Sie können Eigenschaften als virtuell deklarieren und überschreiben, während Sie dies für öffentliche Mitgliedsfelder nicht tun können.

Zaid Masud
quelle
10

Es geht um Versionierung und API-Stabilität. In Version 1 gibt es keinen Unterschied - aber später, wenn Sie entscheiden, dass Sie dies zu einer Eigenschaft mit einer Art Fehlerprüfung in Version 2 machen müssen, müssen Sie Ihre API nicht ändern - keine Codeänderungen, irgendwo anders als die Definition der Eigenschaft.

Reed Copsey
quelle
10

Ein weiterer Vorteil von automatisch implementierten Eigenschaften gegenüber öffentlichen Feldern besteht darin, dass Sie Set-Accessoren privat oder geschützt machen können, wodurch die Klasse von Objekten, für die sie definiert wurde, besser gesteuert werden kann als die von öffentlichen Feldern.

Arnaldo
quelle
8

Es ist nichts Falsches daran, ein Feld zu erstellen public. Denken Sie jedoch daran, dass das Erstellen getter/settermit privateFeldern keine Kapselung ist. IMO, wenn Sie sich nicht für andere Funktionen von a interessieren Property, können Sie es genauso gut machen public.

fastcodejava
quelle
1

Wenn Sie später entscheiden, ob der Titel eindeutig ist, indem Sie ihn mit einer Sammlung oder einer Datenbank vergleichen, können Sie dies in der Eigenschaft tun, ohne den davon abhängigen Code zu ändern.

Wenn Sie nur ein öffentliches Attribut verwenden, haben Sie weniger Flexibilität.

Die zusätzliche Flexibilität ohne Vertragsbruch ist für mich das Wichtigste bei der Verwendung von Eigenschaften. Bis ich die Flexibilität tatsächlich benötige, ist die automatische Generierung am sinnvollsten.

James Black
quelle
0

Eine Sache, die ich ebenso nützlich finde wie alle Code- und Testgründe, ist, dass wenn es sich um eine Eigenschaft gegenüber einem Feld handelt, die Visual Studio-IDE Ihnen die Referenzen für eine Eigenschaft, aber kein Feld anzeigt.

TrtlBoy
quelle
0

Mein Pov hat danach einige Nachforschungen angestellt

  1. Validierung.
  2. Ermöglichen Sie dem Überschreiben des Accessors, das Verhalten einer Eigenschaft zu ändern.
  3. Debugging-Zweck. Wir können wissen, wann und was sich an der Eigenschaft ändert, indem wir im Accessor einen Haltepunkt setzen.
  4. Wir können nur ein Feldset haben. Zum Beispiel public set () und private get (). Dies ist im öffentlichen Bereich nicht möglich.

Es gibt uns wirklich mehr Möglichkeiten und Erweiterbarkeit.

KunYu Tsai
quelle