Unterschied zwischen Eigenschaft und Feld in C # 3.0+

140

Mir ist klar, dass es ein Duplikat von Was ist der Unterschied zwischen einem Feld und einer Eigenschaft in C # zu sein scheint ? aber meine Frage hat einen kleinen Unterschied (aus meiner Sicht):

Sobald ich das weiß

  • Ich werde meine Klasse nicht mit "Techniken, die nur auf Eigenschaften funktionieren" und verwenden
  • Ich werde keinen Validierungscode im Getter / Setter verwenden.

Gibt es einen Unterschied (mit Ausnahme des Stils / der zukünftigen Entwicklung), wie z. B. eine Art Steuerung beim Festlegen der Eigenschaft?

Gibt es einen zusätzlichen Unterschied zwischen:

public string MyString { get; set; }

und

public string myString;

(Mir ist bekannt, dass die erste Version C # 3.0 oder höher erfordert und dass der Compiler die privaten Felder erstellt.)

p4bl0
quelle
Mögliches Duplikat von automatisch implementierten Gettern und
Setzern im Vergleich zu

Antworten:

117

Verkapselung.

In der zweiten Instanz haben Sie gerade eine Variable definiert, in der ersten gibt es einen Getter / Setter um die Variable. Wenn Sie also entscheiden, dass Sie die Variable zu einem späteren Zeitpunkt validieren möchten, ist dies viel einfacher.

Außerdem werden sie in Intellisense anders angezeigt :)

Bearbeiten: Update für OPs aktualisierte Frage - Wenn Sie die anderen Vorschläge hier ignorieren möchten, ist der andere Grund, dass es einfach kein gutes OO-Design ist. Und wenn Sie keinen guten Grund dafür haben, wählen Sie immer eine Eigenschaft über einer öffentlichen Variablen / einem öffentlichen Feld.

Mark Ingram
quelle
9
Warum wird es einfacher sein? Was hindert mich daran, ein Feld in eine Eigenschaft umzuwandeln und ein privates Hintergrundfeld hinzuzufügen? Wie wirkt sich das auf das Aufrufen von Code aus?
Serge Wautier
30
@Serge - Betrifft bereits kompilierten Code. Wenn Sie beispielsweise eine Bibliothek entwickeln, die von mehreren Anwendungen verwendet wird, muss zum Ändern eines Felds in eine Eigenschaft in dieser Bibliothek jede Anwendung neu kompiliert werden. Wenn es sich um eine Eigenschaft handelt, können Sie die Eigenschaft ohne Bedenken aktualisieren.
Dustin Campbell
Ich stimme Ihnen voll und ganz zu, ich benutze immer Eigenschaften. Ich war nur neugierig auf einen möglichen Unterschied
p4bl0
24
Wenn konsumierender Code immer zur gleichen Zeit wie die betroffene Klasse neu kompiliert wird (also ist alles, was privat oder intern ohne Interna ist, 100% sicher), ist es vollkommen in Ordnung, ihn zu einem Feld zu machen
ShuggyCoUk
1
wow Shuggy, dein Kommentar ist genau die Antwort, nach der ich gesucht habe!
p4bl0
160

Felder und Eigenschaften sehen gleich aus, sind es aber nicht. Eigenschaften sind Methoden, und als solche gibt es bestimmte Dinge, die für Eigenschaften nicht unterstützt werden, und einige Dinge, die bei Eigenschaften auftreten können, bei Feldern jedoch niemals.

Hier ist eine Liste der Unterschiede:

  • Felder können als Eingabe für out/refArgumente verwendet werden. Eigenschaften können nicht.
  • Ein Feld liefert immer das gleiche Ergebnis, wenn es mehrmals aufgerufen wird (wenn Probleme mit mehreren Threads weggelassen werden). Eine Eigenschaft wie DateTime.Nowist nicht immer gleich sich selbst.
  • Eigenschaften können Ausnahmen auslösen - Felder werden das niemals tun.
  • Eigenschaften können Nebenwirkungen haben oder die Ausführung kann sehr lange dauern. Felder haben keine Nebenwirkungen und sind immer so schnell, wie es für den jeweiligen Typ zu erwarten ist.
  • Eigenschaften unterstützen unterschiedliche Zugänglichkeit für Getter / Setter - Felder nicht (aber Felder können erstellt werden readonly)
  • Bei Verwendung der Reflexion werden die Eigenschaften und Felder als unterschiedlich behandelt, MemberTypessodass sie unterschiedlich angeordnet sind (im GetFieldsVergleich GetPropertieszu beispielsweise).
  • Der JIT-Compiler behandelt den Eigenschaftszugriff möglicherweise ganz anders als den Feldzugriff. Es kann jedoch bis zu identischem nativem Code kompiliert werden, aber der Spielraum für Unterschiede ist vorhanden.
Brian Rasmussen
quelle
11
Beachten Sie jedoch, dass einige dieser Punkte keine Unterschiede darstellen sollten , wenn bewährte Verfahren angewendet werden. Das heißt, Eigenschaften sollten niemals Nebenwirkungen haben und auch nicht lange dauern, bis sie ausgeführt werden.
Noldorin
15
@Noldorin: Ich bin damit einverstanden, aber leider sollte ist hier das Stichwort. Bei Feldern ist dieses Verhalten garantiert. Ich sage nicht, dass Sie Felder verwenden sollten, aber es ist wichtig, sich der semantischen Unterschiede bewusst zu sein.
Brian Rasmussen
4
Ja, fair genug. Anfänger Programmierer haben leider oft keine Ahnung von diesen Dingen ...
Noldorin
2
Außerdem können Felder einen Feldinitialisierer haben, während Eigenschaften in einem Konstruktor initialisiert werden müssen.
Dio F
3
Ich denke, diese Antwort ist um Größenordnungen besser als die akzeptierte Antwort. Ich fange an zu denken, dass die "akzeptable" Art, Eigenschaften immer Feldern vorzuziehen, schlechtes Denken ist. Wenn Sie nur mit Daten arbeiten müssen, verwenden Sie ein Feld. Wenn Sie Funktionen auf Daten anwenden müssen, verwenden Sie eine Methode. Da Eigenschaften Nebenwirkungen haben können, die Sie nicht kennen (insbesondere wenn Sie die Bibliothek nicht entworfen haben und nur wenig Dokumentation haben), erscheinen sie mir in den meisten Fällen kontraintuitiv.
David Peterson
41

Ein paar schnelle, offensichtliche Unterschiede

  1. Eine Eigenschaft kann Accessor-Schlüsselwörter haben.

    public string MyString { get; private set; }
  2. Eine Eigenschaft kann in Nachkommen überschrieben werden.

    public virtual string MyString { get; protected set; }
Dustin Campbell
quelle
1
mmh .. nr 2 ist interessant .. ich habe nicht daran gedacht
p4bl0
14

Der grundlegende Unterschied besteht darin, dass ein Feld eine Position im Speicher ist, an der Daten des angegebenen Typs gespeichert werden. Eine Eigenschaft stellt eine oder zwei Codeeinheiten dar, die ausgeführt werden, um einen Wert des angegebenen Typs abzurufen oder festzulegen. Die Verwendung dieser Zugriffsmethoden wird syntaktisch ausgeblendet, indem ein Element verwendet wird, das sich wie ein Feld zu verhalten scheint (da es auf beiden Seiten einer Zuweisungsoperation angezeigt werden kann).

AnthonyWJones
quelle
11

Accessoren sind mehr als Felder. Andere haben bereits auf einige wichtige Unterschiede hingewiesen, und ich werde noch einen hinzufügen.

Eigenschaften nehmen an Schnittstellenklassen teil. Beispielsweise:

interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

Diese Schnittstelle kann auf verschiedene Arten erfüllt werden. Beispielsweise:

class Person: IPerson
{
    private string _name;
    public string FirstName
    {
        get
        {
            return _name ?? string.Empty;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException("value");
            _name = value;
        }
    }
    ...
}

In dieser Implementierung schützen wir sowohl die PersonKlasse davor, in einen ungültigen Zustand zu gelangen, als auch den Aufrufer davor, null aus der nicht zugewiesenen Eigenschaft herauszuholen.

Aber wir könnten das Design noch weiter vorantreiben. Beispielsweise kann die Schnittstelle nicht mit dem Setter umgehen. Es ist durchaus legitim zu sagen, dass Verbraucher von IPersonSchnittstellen nur daran interessiert sind, die Immobilie zu erhalten, nicht daran, sie festzulegen:

interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}

Die vorherige Implementierung der PersonKlasse erfüllt diese Schnittstelle. Die Tatsache, dass der Anrufer auch die Eigenschaften festlegen kann, ist aus Sicht der Verbraucher (die konsumieren IPerson) bedeutungslos . Zusätzliche Funktionen der konkreten Implementierung werden beispielsweise vom Builder berücksichtigt:

class PersonBuilder: IPersonBuilder
{
    IPerson BuildPerson(IContext context)
    {

        Person person = new Person();

        person.FirstName = context.GetFirstName();
        person.LastName = context.GetLastName();

        return person;

    }
}

...

void Consumer(IPersonBuilder builder, IContext context)
{
    IPerson person = builder.BuildPerson(context);
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

In diesem Code weiß der Verbraucher nichts über Immobiliensetzer - es ist nicht seine Aufgabe, davon zu wissen. Der Verbraucher braucht nur Getter, und er bekommt Getter von der Schnittstelle, dh vom Vertrag.

Eine weitere vollständig gültige Implementierung IPersonwäre eine unveränderliche Personenklasse und eine entsprechende Personenfabrik:

class Person: IPerson
{
    public Person(string firstName, string lastName)
    {

        if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
            throw new System.ArgumentException();

        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

}

...

class PersonFactory: IPersonFactory
{
    public IPerson CreatePerson(string firstName, string lastName)
    {
        return new Person(firstName, lastName);
    }
}
...
void Consumer(IPersonFactory factory)
{
    IPerson person = factory.CreatePerson("John", "Doe");
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

In diesem Codebeispiel hat der Verbraucher erneut keine Kenntnis vom Ausfüllen der Eigenschaften. Der Verbraucher befasst sich nur mit Gettern, und die konkrete Implementierung (und die dahinter stehende Geschäftslogik, wie das Testen, ob der Name leer ist) bleibt den spezialisierten Klassen - Bauherren und Fabriken - überlassen. All diese Operationen sind mit Feldern absolut unmöglich.

Zoran Horvat
quelle
7

Der erste:

public string MyString {get; set; }

ist eine Eigenschaft; Das zweite ( public string MyString) bezeichnet ein Feld.

Der Unterschied besteht darin, dass bestimmte Techniken (ASP.NET-Datenbindung für Instanzen) nur für Eigenschaften und nicht für Felder funktionieren. Gleiches gilt für die XML-Serialisierung: Nur Eigenschaften werden serialisiert, Felder werden nicht serialisiert.

Frederik Gheysels
quelle
8
Falsch. XML-Serialisierung Serialisiert öffentliche Felder.
Serge Wautier
2
Vielleicht. Wenn Sie jedoch eine Objektdatenquelle aus einer Klasse erstellen, können Sie nur die Eigenschaften verwenden, nicht die Felder. (Es sei denn, ich habe etwas falsch gemacht: P)
Svish
Gut ist zu TROCKEN;) aber ich schreibe noch einmal, ich mag starke Rolle von Eigentum in C # Sprache. Ist viel besser implementiert als in Java (folglich von Anfang an) Viele, vielleicht alle .net-Lösungen funktionieren nur mit Eigenschaften. WPF, ASPX und mehr.
Jacek Cz
3

Eigenschaften und Felder scheinen in vielen Fällen ähnlich zu sein, sind es aber nicht. Es gibt Einschränkungen für Eigenschaften, die für Felder nicht vorhanden sind, und umgekehrt.

Wie andere schon erwähnt haben. Sie können eine Eigenschaft schreibgeschützt oder schreibgeschützt machen, indem Sie ihren Accessor privat machen. Das kann man mit einem Feld nicht machen. Eigenschaften können auch virtuell sein, Felder jedoch nicht.

Stellen Sie sich Eigenschaften als syntaktischen Zucker für die Funktionen getXXX () / setXXX () vor. So werden sie hinter den Kulissen umgesetzt.

Erik Funkenbusch
quelle
1

Es gibt noch einen weiteren wichtigen Unterschied zwischen Feldern und Eigenschaften.

Bei Verwendung von WPF können Sie nur an öffentliche Eigenschaften binden. Die Bindung an ein öffentliches Feld funktioniert nicht . Dies gilt auch dann INotifyPropertyChanged, wenn Sie nicht implementieren (obwohl Sie dies immer tun sollten).

BradleyDotNET
quelle
Gut ist zu TROCKEN;) aber ich schreibe noch einmal, ich mag starke Rolle von Eigentum in C # Sprache. Ist viel besser implementiert als in Java (folglich von Anfang an) Viele, vielleicht alle .net-Lösungen funktionieren nur mit Eigenschaften. WPF, ASPX und mehr.
Jacek Cz
1

Neben anderen Antworten und Beispielen halte ich dieses Beispiel in einigen Situationen für nützlich.

Angenommen, Sie haben Folgendes:OnChange property

public Action OnChange { get; set; }

Wenn Sie Verwendung Delegierten wollen als müssen Sie es ändern OnChangezu fielddieser mag:

public event Action OnChange = delegate {};

In einer solchen Situation schützen wir unser Feld vor unerwünschtem Zugriff oder Änderungen.

Maytham-ɯɐɥʇʎɐɯ
quelle
0

Sie sollten für öffentliche Felder immer Eigenschaften anstelle von Feldern verwenden. Dadurch wird sichergestellt, dass Ihre Bibliothek bei Bedarf die Kapselung für jedes Feld implementieren kann, ohne die vorhandenen Codes zu beschädigen. Wenn Sie die Felder durch Eigenschaften in vorhandenen Bibliotheken ersetzen, werden alle Abhängige Module, die Ihre Bibliothek verwenden, müssen ebenfalls neu erstellt werden.

user1849310
quelle
"immer" ist ein wenig zu hartes Wort. In C # (besser als in Java) hat die Eigenschaft eine starke Position, ist (wahrscheinlich ausnahmslos) Haupt- / Bindungsmethode in ASP, WPF und anderen. Trotzdem kann ich mir vorstellen, dass Design mit Feld, das kein Eigentum ist, (manchmal) Sinn hat
Jacek Cz