Warum sollte ich die Verwendung von Eigenschaften in C # vermeiden?

102

In seinem ausgezeichneten Buch CLR Via C # sagte Jeffrey Richter, dass er Immobilien nicht mag und empfiehlt, sie nicht zu verwenden. Er gab einen Grund an, aber ich verstehe nicht wirklich. Kann mir jemand erklären, warum ich Eigenschaften verwenden sollte oder nicht? Ändert sich dies in C # 3.0 mit automatischen Eigenschaften?

Als Referenz habe ich Jeffrey Richters Meinungen hinzugefügt:

• Eine Eigenschaft kann schreibgeschützt oder schreibgeschützt sein. Der Feldzugriff ist immer lesbar und beschreibbar. Wenn Sie eine Eigenschaft definieren, ist es am besten, Accessor-Methoden zum Abrufen und Festlegen anzubieten.

• Eine Eigenschaftsmethode kann eine Ausnahme auslösen. Der Feldzugriff löst niemals eine Ausnahme aus.

• Eine Eigenschaft kann nicht als out- oder ref-Parameter an eine Methode übergeben werden. ein Feld kann. Der folgende Code wird beispielsweise nicht kompiliert:

using System;
public sealed class SomeType
{
   private static String Name 
   {
     get { return null; }
     set {}
   }
   static void MethodWithOutParam(out String n) { n = null; }
   public static void Main()
   {
      // For the line of code below, the C# compiler emits the following:
      // error CS0206: A property or indexer may not
      // be passed as an out or ref parameter
      MethodWithOutParam(out Name);
   }
}

• Die Ausführung einer Eigenschaftsmethode kann lange dauern. Der Feldzugriff wird immer sofort abgeschlossen. Ein häufiger Grund für die Verwendung von Eigenschaften ist die Durchführung einer Thread-Synchronisierung, die den Thread für immer stoppen kann. Daher sollte eine Eigenschaft nicht verwendet werden, wenn eine Thread-Synchronisierung erforderlich ist. In dieser Situation wird ein Verfahren bevorzugt. Wenn auf Ihre Klasse remote zugegriffen werden kann (z. B. wird Ihre Klasse von System.MashalByRefObject abgeleitet), ist der Aufruf der Eigenschaftsmethode sehr langsam. Daher wird eine Methode einer Eigenschaft vorgezogen. Meiner Meinung nach sollten von MarshalByRefObject abgeleitete Klassen niemals Eigenschaften verwenden.

• Wenn eine Eigenschaftsmethode mehrmals hintereinander aufgerufen wird, kann sie jedes Mal einen anderen Wert zurückgeben. Ein Feld gibt jedes Mal den gleichen Wert zurück. Die System.DateTime-Klasse verfügt über eine schreibgeschützte Now-Eigenschaft, die das aktuelle Datum und die aktuelle Uhrzeit zurückgibt. Jedes Mal, wenn Sie diese Eigenschaft abfragen, wird ein anderer Wert zurückgegeben. Dies ist ein Fehler, und Microsoft wünscht sich, dass die Klasse behoben werden kann, indem Now anstelle einer Eigenschaft zu einer Methode gemacht wird.

• Eine Eigenschaftsmethode kann beobachtbare Nebenwirkungen verursachen. Feldzugriff nie. Mit anderen Worten, ein Benutzer eines Typs sollte in der Lage sein, verschiedene von einem Typ definierte Eigenschaften in beliebiger Reihenfolge festzulegen, ohne ein anderes Verhalten des Typs zu bemerken.

• Eine Eigenschaftsmethode erfordert möglicherweise zusätzlichen Speicher oder gibt einen Verweis auf etwas zurück, das nicht Teil des Objektstatus ist. Das Ändern des zurückgegebenen Objekts hat daher keine Auswirkungen auf das ursprüngliche Objekt. Das Abfragen eines Feldes gibt immer einen Verweis auf ein Objekt zurück, das garantiert Teil des ursprünglichen Objektstatus ist. Das Arbeiten mit einer Eigenschaft, die eine Kopie zurückgibt, kann für Entwickler sehr verwirrend sein, und diese Eigenschaft wird häufig nicht dokumentiert.

Quan Mai
quelle
11
Ich besitze die 3. Ausgabe von 'CLR via C #' und auf Seite 242 sagt Herr Richter, dass er persönlich keine Eigenschaften mag, aber er empfiehlt niemals, sie nicht zu verwenden. Bitte geben Sie die Buchversion und die Seitenzahl an, auf der Sie dies gelesen haben.
Kirk.burleson

Antworten:

173

Jeffs Grund für die Abneigung gegen Eigenschaften ist, dass sie wie Felder aussehen. Entwickler, die den Unterschied nicht verstehen, behandeln sie also wie Felder, vorausgesetzt, sie sind billig in der Ausführung usw.

Persönlich stimme ich ihm in diesem Punkt nicht zu - ich finde, dass Eigenschaften den Client-Code viel einfacher zu lesen machen als die entsprechenden Methodenaufrufe. Ich bin damit einverstanden, dass Entwickler wissen müssen, dass Eigenschaften im Grunde genommen verschleierte Methoden sind - aber ich denke, dass es besser ist, Entwickler darüber aufzuklären, als das Lesen von Code mithilfe von Methoden zu erschweren. (Insbesondere nachdem ich gesehen habe, dass Java-Code mit mehreren Gettern und Setzern in derselben Anweisung aufgerufen wird, weiß ich, dass der entsprechende C # -Code viel einfacher zu lesen wäre. Das Gesetz von Demeter ist theoretisch alles sehr gut, aber manchmal foo.Name.Lengthwirklich das Richtige ...)

(Und nein, automatisch implementierte Eigenschaften ändern daran nichts.)

Dies ist ein bisschen wie die Argumente gegen die Verwendung von Erweiterungsmethoden - ich kann die Argumentation verstehen, aber der praktische Nutzen (wenn er sparsam verwendet wird) überwiegt aus meiner Sicht den Nachteil.

Jon Skeet
quelle
Vielen Dank für Ihre Antwort! Über Argumente gegen die Verwendung von Erweiterungsmethoden: Sprechen Sie über ein Thema von Jeffrey Richter oder abstrakt?
Abatishchev
@abatishchev: Es war nur ein allgemeiner Punkt über Erweiterungsmethoden. Es ist nicht direkt mit Eigenschaften verbunden.
Jon Skeet
Ich würde weiter gehen. Mit Ausnahme des Leistungsaspekts verstehe ich nicht, warum ein Programmierer WISSEN sollte, ob etwas ein Feld oder eine Eigenschaft ist. Er sollte es als ein Attribut einer Instanz betrachten, das den STAAT der Objektinstanz kennzeichnet, und die Objektimplementierung sollte sich um alle Änderungen ihres Zustands kümmern (innerhalb des Vertrags der Klasse). Eigenschaften können also in einigen Fällen genauso gut Felder sein oder in anderen zu Feldern werden, wenn möglicherweise eine Neugestaltung der Implementierung der Klasse vorgenommen wird. Die Entscheidung zwischen einem Feld oder einer Immobilie hängt dann davon ab, wie viel Schutz der Staat benötigt, um konsequent zu bleiben.
TheBlastOne
1
@PatrickFromberg: Sie haben eine große Menge Code verpasst, der anscheinend schreibgeschützte Felder verwendet. Es gibt nichts zu sagen, dass Eigenschaften Veränderlichkeit implizieren. Ich habe oft schreibgeschützte Felder, die schreibgeschützte Eigenschaften unterstützen. Halten Sie das für eine schlechte Sache?
Jon Skeet
1
@Patrick: Nein, es bietet den Vorteil, dass die API von der Implementierung getrennt wird. Sie können später ändern, wie die Eigenschaft aus dem Feld berechnet wird (z. B. um zwei verwandte Eigenschaften aus einem Feld zu berechnen).
Jon Skeet
34

Nehmen wir seine Argumente einzeln:

Eine Eigenschaft kann schreibgeschützt oder schreibgeschützt sein. Der Feldzugriff ist immer lesbar und beschreibbar.

Dies ist ein Gewinn für Immobilien, da Sie eine genauere Kontrolle über den Zugriff haben.

Eine Eigenschaftsmethode kann eine Ausnahme auslösen. Der Feldzugriff löst niemals eine Ausnahme aus.

Während dies meistens zutrifft, können Sie sehr gut eine Methode für ein nicht initialisiertes Objektfeld aufrufen und eine Ausnahme auslösen lassen.

• Eine Eigenschaft kann nicht als out- oder ref-Parameter an eine Methode übergeben werden. ein Feld kann.

Messe.

• Die Ausführung einer Eigenschaftsmethode kann lange dauern. Der Feldzugriff wird immer sofort abgeschlossen.

Es kann auch sehr wenig Zeit dauern.

• Wenn eine Eigenschaftsmethode mehrmals hintereinander aufgerufen wird, kann sie jedes Mal einen anderen Wert zurückgeben. Ein Feld gibt jedes Mal den gleichen Wert zurück.

Nicht wahr. Woher wissen Sie, dass sich der Wert des Felds nicht geändert hat (möglicherweise durch einen anderen Thread)?

Die System.DateTime-Klasse verfügt über eine schreibgeschützte Now-Eigenschaft, die das aktuelle Datum und die aktuelle Uhrzeit zurückgibt. Jedes Mal, wenn Sie diese Eigenschaft abfragen, wird ein anderer Wert zurückgegeben. Dies ist ein Fehler, und Microsoft wünscht sich, dass die Klasse behoben werden kann, indem Now anstelle einer Eigenschaft zu einer Methode gemacht wird.

Wenn es ein Fehler ist, ist es ein kleiner.

• Eine Eigenschaftsmethode kann beobachtbare Nebenwirkungen verursachen. Feldzugriff nie. Mit anderen Worten, ein Benutzer eines Typs sollte in der Lage sein, verschiedene von einem Typ definierte Eigenschaften in beliebiger Reihenfolge festzulegen, ohne ein anderes Verhalten des Typs zu bemerken.

Messe.

• Eine Eigenschaftsmethode erfordert möglicherweise zusätzlichen Speicher oder gibt einen Verweis auf etwas zurück, das nicht Teil des Objektstatus ist. Das Ändern des zurückgegebenen Objekts hat daher keine Auswirkungen auf das ursprüngliche Objekt. Das Abfragen eines Feldes gibt immer einen Verweis auf ein Objekt zurück, das garantiert Teil des ursprünglichen Objektstatus ist. Das Arbeiten mit einer Eigenschaft, die eine Kopie zurückgibt, kann für Entwickler sehr verwirrend sein, und diese Eigenschaft wird häufig nicht dokumentiert.

Die meisten Proteste waren auch für Javas Getter und Setter zu sagen - und wir hatten sie eine ganze Weile ohne solche Probleme in der Praxis.

Ich denke, die meisten Probleme könnten durch eine bessere Syntaxhervorhebung (dh das Unterscheiden von Eigenschaften von Feldern) gelöst werden, damit der Programmierer weiß, was ihn erwartet.

Hejazzman
quelle
3
"Die Probleme könnten durch eine bessere Syntaxhervorhebung gelöst werden" : Wie oft verwenden Sie öffentliche Felder? Private Felder haben normalerweise einen anderen Stil, z _field. Oder einfach nur Kleinbuchstaben field.
Steven Jeuris
18

Ich habe das Buch nicht gelesen und Sie haben den Teil nicht zitiert, den Sie nicht verstehen, also muss ich raten.

Einige Leute mögen keine Eigenschaften, weil sie Ihren Code dazu bringen können, überraschende Dinge zu tun.

Wenn ich tippe Foo.Bar, erwarten die Leser normalerweise, dass dies einfach auf ein Mitgliedsfeld der Foo-Klasse zugreift. Es ist eine billige, fast kostenlose Operation und deterministisch. Ich kann es immer und immer wieder aufrufen und jedes Mal das gleiche Ergebnis erzielen.

Stattdessen kann es sich bei Eigenschaften tatsächlich um einen Funktionsaufruf handeln. Es könnte eine Endlosschleife sein. Möglicherweise wird eine Datenbankverbindung geöffnet. Bei jedem Zugriff werden möglicherweise andere Werte zurückgegeben.

Es ist ein ähnliches Argument, warum Linus C ++ hasst. Ihr Code kann für den Leser überraschend wirken. Er hasst das Überladen von Bedienern: a + bbedeutet nicht unbedingt eine einfache Hinzufügung. Dies kann eine äußerst komplizierte Operation bedeuten, genau wie die C # -Eigenschaften. Es kann Nebenwirkungen haben. Es kann alles tun.

Ehrlich gesagt denke ich, dass dies ein schwaches Argument ist. Beide Sprachen sind voll von solchen Dingen. (Sollten wir auch in C # eine Überladung des Operators vermeiden? Schließlich kann dort dasselbe Argument verwendet werden.)

Eigenschaften ermöglichen Abstraktion. Wir können so tun , als wäre etwas ein reguläres Feld, und es so verwenden, als wäre es eines, und müssen uns keine Gedanken darüber machen, was sich hinter den Kulissen abspielt.

Das wird normalerweise als eine gute Sache angesehen, aber es hängt offensichtlich davon ab, dass der Programmierer aussagekräftige Abstraktionen schreibt. Ihre Eigenschaften sollten sich wie Felder verhalten. Sie sollten keine Nebenwirkungen haben, sie sollten keine teuren oder unsicheren Operationen durchführen. Wir wollen sie als Felder betrachten können.

Ich habe jedoch einen anderen Grund, sie nicht perfekt zu finden. Sie können nicht durch Verweis auf andere Funktionen übergeben werden.

Felder können als übergeben werden ref, sodass eine aufgerufene Funktion direkt darauf zugreifen kann. Funktionen können als Delegaten übergeben werden, sodass eine aufgerufene Funktion direkt darauf zugreifen kann.

Eigenschaften ... können nicht.

Das ist Scheiße.

Das heißt aber nicht, dass Eigenschaften böse sind oder nicht verwendet werden sollten. Für viele Zwecke sind sie großartig.

jalf
quelle
3
Mein Argument ist, dass Sie zunächst nicht davon ausgehen sollten, dass es sich um ein Feld handelt. Wenn Sie es von einer anderen Klasse aus aufrufen, sollten Sie ohnehin keinen Zugriff auf nicht konstante Felder haben, da diese privat sein sollten. (Es gibt auch die Namenskonvention, um Sie zu informieren.)
Jon Skeet
1
Ja ich stimme zu. Das Argument scheint sich auf "Ich bin es gewohnt, dass diese Syntax nur für Felder verwendet wird. Daher ist es schlecht, sie auf andere Fälle auszudehnen" zu beschränken. Und die offensichtliche Antwort lautet: "Nun, gewöhnen Sie sich daran, andere Fälle abzudecken, und es wird nicht schlecht." ;)
Jalf
Ich wünschte, .net-Sprachen würden ein Standardmittel bereitstellen, mit dem eine Klasse Eigenschaften als refParameter verfügbar macht. ein Mitglied (z. B. Foo) eines Formulars void Foo<T>(ActionByRef<Point,T> proc, ref T param)mit einem speziellen Attribut, in das der Compiler umgewandelt thing.Foo.X+=someVar;wird Foo((ref Point it, ref int param)=>it.X += param, ref someVar);. Da das Lambda ein statischer Delegat ist, wäre kein Abschluss erforderlich, und der Benutzer eines Objekts könnte jeden Speicherort, der die Eigenschaft unterstützt, als echten refParameter verwenden (und ihn als refParameter an andere Methoden übergeben ).
Supercat
Das manuelle Schreiben des Lambda erzeugt einen wirklich icky aussehenden Quellcode, aber deshalb wäre es hilfreich, wenn der Compiler die Transformation durchführt. Der Code für eine Klasse zum Offenlegen einer "Callback-by-Ref" -Eigenschaft wäre ziemlich vernünftig. Der Code ist auf der Anruferseite nur hässlich (ohne Transformation).
Supercat
Bitte haben Sie Verständnis dafür, dass eine Eigenschaft ein als Mitglied getarnter Funktionsaufruf ist, sodass sie nicht mehr als Referenz übergeben werden kann, als Sie die öffentlichen Funktionen einer Klasse übergeben können. Sie können jederzeit ein öffentliches Mitglied verwenden, wenn Sie dies auf diese Weise beabsichtigen. Eine Eigenschaft ist ein intelligentes Mitglied. Sie kann eine Ausnahme für ungültige Daten auslösen, die an set übergeben werden.
Diceyus
17

Im Jahr 2009 schien dieser Rat lediglich ein Bauchweh der Sorte Who Moved My Cheese zu sein . Heute ist es fast lächerlich veraltet.

Ein sehr wichtiger Punkt, den viele Antworten auf Zehenspitzen zu beantworten scheinen, aber nicht direkt ansprechen, ist, dass diese angeblichen "Gefahren" von Eigenschaften ein absichtlicher Bestandteil des Framework-Designs sind!

Ja, Eigenschaften können:

  • Geben Sie verschiedene Zugriffsmodifikatoren für den Getter und den Setter an. Dies ist ein Vorteil gegenüber Feldern. Ein übliches Muster besteht darin, einen öffentlichen Getter und einen geschützten oder internen Setter zu haben, eine sehr nützliche Vererbungstechnik, die nur von Feldern allein erreicht werden kann.

  • Eine Ausnahme auslösen. Bis heute ist dies eine der effektivsten Methoden zur Validierung, insbesondere bei der Arbeit mit UI-Frameworks, die Datenbindungskonzepte beinhalten. Es ist viel schwieriger sicherzustellen, dass ein Objekt bei der Arbeit mit Feldern in einem gültigen Zustand bleibt.

  • Die Ausführung dauert lange. Der gültige Vergleich ist hier mit Methoden , die gleich lange dauern - keine Felder . Für die Aussage "eine Methode wird bevorzugt" wird keine andere Grundlage angegeben als die persönliche Präferenz eines Autors.

  • Gibt bei nachfolgenden Ausführungen andere Werte von seinem Getter zurück. Dies scheint fast wie ein Witz in unmittelbarer Nähe zu dem Punkt, an dem die Tugenden von ref/ outparameter mit Feldern gepriesen werden, deren Wert eines Feldes nach einem ref/ out-Aufruf garantiert und unvorhersehbar von seinem vorherigen Wert abweicht.

    Wenn wir über den spezifischen (und praktisch akademischen) Fall eines Single-Threaded-Zugriffs ohne afferente Kopplungen sprechen, ist es ziemlich gut verstanden, dass es nur ein schlechtes Eigenschaftsdesign ist, Nebenwirkungen zu haben, die den sichtbaren Zustand ändern, und vielleicht ist es mein Gedächtnis verblassen, aber ich kann mich einfach nicht an Beispiele erinnern, bei denen Leute DateTime.Nowjedes Mal den gleichen Wert verwenden und erwarten, dass er herauskommt. Zumindest keine Fälle, in denen sie es mit einer Hypothese nicht genauso schlimm vermasselt hätten DateTime.Now().

  • Verursachen Sie beobachtbare Nebenwirkungen - und das ist natürlich genau der Grund, warum Eigenschaften überhaupt als Sprachmerkmal erfunden wurden. Laut den Microsoft- Richtlinien für das Eigenschaftsdesign sollte die Setterreihenfolge keine Rolle spielen, da dies sonst eine zeitliche Kopplung implizieren würde . Natürlich können Sie keine zeitliche Kopplung mit Feldern allein erreichen, aber das liegt nur daran, dass Sie mit Feldern allein überhaupt kein bedeutungsvolles Verhalten verursachen können, bis eine Methode ausgeführt wird.

    Eigenschaftszugriffsmethoden können tatsächlich dazu beitragen , bestimmte Arten der zeitlichen Kopplung zu verhindern, indem sie das Objekt in einen gültigen Zustand versetzen, bevor eine Aktion ausgeführt wird. Wenn beispielsweise eine Klasse ein StartDateund ein hat EndDate, können Sie auch das EndDateVorher- Setzen StartDatefestlegen, um das StartDateZurück zu erzwingen . Dies gilt auch in Umgebungen mit mehreren Threads oder asynchronen Umgebungen, einschließlich des offensichtlichen Beispiels einer ereignisgesteuerten Benutzeroberfläche.

Andere Dinge, die Eigenschaften tun können, die Felder nicht enthalten können:

  • Lazy Loading , eine der effektivsten Methoden, um Fehler bei der Initialisierungsreihenfolge zu vermeiden.
  • Änderungsbenachrichtigungen , die so ziemlich die gesamte Basis für die MVVM- Architektur bilden.
  • Vererbung , zum Beispiel das Definieren einer abstrakten Typeoder Nameso abgeleiteten Klasse, kann interessante, aber dennoch konstante Metadaten über sich selbst liefern.
  • Abfangen dank der oben genannten.
  • Indexer , die jeder, der jemals mit COM Interop und der unvermeidlichen Anzahl von Item(i)Anrufen arbeiten musste, als wunderbare Sache erkennen wird.
  • Arbeiten Sie mit PropertyDescriptor, das für die Erstellung von Designern und für XAML-Frameworks im Allgemeinen unerlässlich ist.

Richter ist eindeutig ein produktiver Autor und weiß viel über CLR und C #, aber ich muss sagen, es scheint, als hätte er diesen Rat ursprünglich geschrieben (ich bin mir nicht sicher, ob er in seinen neueren Revisionen enthalten ist - ich hoffe aufrichtig nicht). dass er einfach alte Gewohnheiten nicht loslassen wollte und Probleme hatte, die Konventionen von C # zu akzeptieren (im Vergleich zu C ++ zum Beispiel).

Damit meine ich, dass sein Argument "Eigenschaften als schädlich angesehen" im Wesentlichen auf eine einzige Aussage hinausläuft : Eigenschaften sehen aus wie Felder, aber sie verhalten sich möglicherweise nicht wie Felder. Und das Problem mit der Aussage ist, dass sie nicht wahr oder bestenfalls sehr irreführend ist. Eigenschaften nicht aussehen wie Felder - zumindest werden sie nicht angenommen , wie Felder zu suchen.

Es gibt zwei sehr starke Codierungskonventionen in C # mit ähnlichen Konventionen, die von anderen CLR-Sprachen geteilt werden, und FXCop wird Sie anschreien, wenn Sie diese nicht befolgen:

  1. Felder sollten immer privat sein, niemals öffentlich.
  2. Felder sollten in camelCase deklariert werden. Eigenschaften sind PascalCase.

Somit besteht keine Unklarheit darüber, ob Foo.Bar = 42es sich um einen Eigenschafts- oder einen Feldzugriff handelt. Es ist ein Eigenschafts-Accessor und sollte wie jede andere Methode behandelt werden - es kann langsam sein, es kann eine Ausnahme auslösen usw. Das liegt in der Natur der Abstraktion - es liegt ganz im Ermessen der deklarierenden Klasse, wie sie reagieren soll. Klassendesigner sollten das Prinzip der geringsten Überraschung anwenden, aber Anrufer sollten nichts von einer Immobilie annehmen, außer dass sie das tut, was sie verspricht. Das ist mit Absicht.

Die Alternative zu Eigenschaften sind Getter / Setter-Methoden überall. Das ist der Java-Ansatz, der von Anfang an umstritten war . Es ist in Ordnung, wenn das deine Tasche ist, aber es ist einfach nicht so, wie wir im .NET-Camp rollen. Wir versuchen, zumindest innerhalb der Grenzen eines statisch typisierten Systems, das zu vermeiden, was Fowler Syntaktisches Rauschen nennt . Wir wollen keine zusätzlichen Klammern, zusätzlichen get/ setWarzen oder zusätzlichen Methodensignaturen - nicht, wenn wir sie ohne Verlust der Klarheit vermeiden können.

Sagen Sie, was Sie wollen, aber es foo.Bar.Baz = quux.Answers[42]wird immer viel einfacher zu lesen sein als foo.getBar().setBaz(quux.getAnswers().getItem(42)). Und wenn Sie täglich Tausende von Zeilen davon lesen, macht das einen Unterschied.

(Und wenn Ihre natürliche Antwort auf den obigen Absatz lautet: "Sicher ist es schwer zu lesen, aber es wäre einfacher, wenn Sie ihn in mehrere Zeilen aufteilen", dann muss ich leider sagen, dass Sie den Punkt völlig verfehlt haben .)

Aaronaught
quelle
11

Ich sehe keine Gründe, warum Sie Eigenschaften im Allgemeinen nicht verwenden sollten.

Automatische Eigenschaften in C # 3+ vereinfachen die Syntax nur ein wenig (a la syntatischer Zucker).

Konstantin Tarkus
quelle
Bitte lesen Sie die Seiten 215-216 in diesem Buch. Ich bin sicher, dass Sie wissen, wer Jeffrey Richter ist!
Quan Mai
Ich habe gelesen (CLR über C #, 2. Aufl.), Stimme seiner Position nicht zu und sehe keine wirklichen Gründe, warum ich keine Eigenschaften verwende!
Abatishchev
Es ist ein gutes Buch, aber ich stimme dem Autor in diesem Moment nicht zu.
Konstantin Tarkus
Wo genau ist der Ort, an dem der Autor vorschlägt, keine Eigenschaften zu verwenden? Habe nichts auf S.215-217 gefunden
Konstantin Tarkus
Ich habe Jeffreys Meinungen in meine Frage aufgenommen :). Sie finden es auf den Seiten 215-216 in gedruckter Ausgabe :)
Quan Mai
9

Es ist nur die Meinung einer Person. Ich habe einige C # -Bücher gelesen und ich habe noch niemanden gesehen, der sagt "benutze keine Eigenschaften".

Ich persönlich denke, dass Eigenschaften eines der besten Dinge an c # sind. Mit ihnen können Sie den Status über einen beliebigen Mechanismus anzeigen. Sie können das erste Mal, wenn etwas verwendet wird, träge instanziieren und das Festlegen eines Werts usw. überprüfen. Wenn Sie sie verwenden und schreiben, stelle ich mir Eigenschaften nur als Setter und Getter vor, die eine viel schönere Syntax haben.

Was die Vorbehalte mit Eigenschaften betrifft, gibt es ein paar. Einer ist wahrscheinlich ein Missbrauch von Eigenschaften, der andere kann subtil sein.

Erstens sind Eigenschaften Arten von Methoden. Es kann überraschend sein, wenn Sie eine komplizierte Logik in eine Eigenschaft einfügen, da die meisten Benutzer einer Klasse erwarten, dass die Eigenschaft ziemlich leicht ist.

Z.B

public class WorkerUsingMethod
{
   // Explicitly obvious that calculation is being done here
   public int CalculateResult()
   { 
      return ExpensiveLongRunningCalculation();
   }
}

public class WorkerUsingProperty
{
   // Not at all obvious.  Looks like it may just be returning a cached result.
   public int Result
   {
       get { return ExpensiveLongRunningCalculation(); }
   }
}

Ich finde, dass die Verwendung von Methoden für diese Fälle hilft, eine Unterscheidung zu treffen.

Zweitens, und was noch wichtiger ist, können Eigenschaften Nebenwirkungen haben, wenn Sie sie beim Debuggen bewerten.

Angenommen, Sie haben eine Eigenschaft wie diese:

public int Result 
{ 
   get 
   { 
       m_numberQueries++; 
       return m_result; 
   } 
}

Angenommen, Sie haben eine Ausnahme, die auftritt, wenn zu viele Abfragen durchgeführt werden. Ratet mal, was passiert, wenn Sie mit dem Debuggen beginnen und die Eigenschaft im Debugger verschieben? Schlechte Dinge. Vermeiden Sie dies! Durch Betrachten der Eigenschaft wird der Status des Programms geändert.

Dies sind die einzigen Einschränkungen, die ich habe. Ich denke, die Vorteile von Immobilien überwiegen bei weitem die Probleme.

Mark Simpson
quelle
6

Dieser Grund muss in einem ganz bestimmten Kontext angegeben worden sein. Es ist normalerweise umgekehrt - es wird empfohlen, Eigenschaften zu verwenden, da diese Ihnen eine Abstraktionsebene bieten, mit der Sie das Verhalten einer Klasse ändern können, ohne die Clients zu beeinflussen ...

Rashack
quelle
+1 für die implizite Hervorhebung der Bedeutung des "Vertrags" zwischen dem Kunden und der Klasseneigenschaft.
TheBlastOne
6

Ich kann nicht anders, als die Details von Jeffrey Richters Meinungen herauszusuchen:

Eine Eigenschaft kann schreibgeschützt oder schreibgeschützt sein. Der Feldzugriff ist immer lesbar und beschreibbar.

Falsch: Felder können als schreibgeschützt markiert werden, sodass nur der Konstruktor des Objekts darauf schreiben kann.

Eine Eigenschaftsmethode kann eine Ausnahme auslösen. Der Feldzugriff löst niemals eine Ausnahme aus.

Falsch: Durch die Implementierung einer Klasse kann der Zugriffsmodifikator eines Felds von öffentlich in privat geändert werden. Versuche, private Felder zur Laufzeit zu lesen, führen immer zu einer Ausnahme.

Cecil hat einen Namen
quelle
5

Ich stimme Jeffrey Richter nicht zu, aber ich kann mir vorstellen, warum er keine Immobilien mag (ich habe sein Buch nicht gelesen).

Obwohl Eigenschaften wie Benutzer (in Bezug auf die Implementierung) sind, erwarte ich als Benutzer einer Klasse, dass sich ihre Eigenschaften "mehr oder weniger" wie ein öffentliches Feld verhalten, z.

  • Es gibt keine zeitaufwändige Operation im Property Getter / Setter
  • Der Property Getter hat keine Nebenwirkungen (mehrmaliger Aufruf, ändert das Ergebnis nicht)

Leider habe ich Eigenschaften gesehen, die sich nicht so verhalten haben. Das Problem sind jedoch nicht die Eigenschaften selbst, sondern die Personen, die sie implementiert haben. Es erfordert also nur etwas Bildung.

M4N
quelle
1
+1, da es die Bedeutung eines sauberen Vertrags hervorhebt. Eine scheinbar schreibgeschützte Eigenschaft, die regelmäßig einen anderen Wert für jede Referenz zurückgibt, ist eine schreibgeschützte Eigenschaft - sie schreibt nur nicht auf ihren eigenen Wert, sondern auf andere Instanzvariablen (direkt oder indirekt). Das ist kein schlechter Stil, sondern muss dokumentiert werden (oder ein impliziter Bestandteil des Vertrags sein).
TheBlastOne
4

Es gibt eine Zeit, in der ich erwäge, keine Eigenschaften zu verwenden, und zwar schriftlich .Net Compact Framework-Code. Der CF-JIT-Compiler führt nicht die gleiche Optimierung wie der Desktop-JIT-Compiler durch und optimiert keine einfachen Eigenschaftszugriffsberechtigten. In diesem Fall führt das Hinzufügen einer einfachen Eigenschaft dazu, dass bei Verwendung eines öffentlichen Felds eine geringe Menge an Code aufgebläht wird. Normalerweise ist dies kein Problem, aber in der Compact Framework-Welt sind Sie fast immer mit engen Speicherbeschränkungen konfrontiert, sodass selbst winzige Einsparungen wie diese zählen.

Steve
quelle
4

Sie sollten es nicht vermeiden, sie zu verwenden, aber Sie sollten sie aus den von anderen Mitwirkenden angegebenen Gründen mit Qualifikation und Sorgfalt verwenden.

Ich habe einmal eine Eigenschaft namens "Kunden" gesehen, die intern einen Out-of-Process-Aufruf einer Datenbank geöffnet und die Kundenliste gelesen hat. Der Client-Code hatte ein 'für (int i to Customers.Count)', was bei jeder Iteration und für den Zugriff des ausgewählten Kunden einen separaten Aufruf der Datenbank verursachte. Dies ist ein ungeheuerliches Beispiel, das das Prinzip demonstriert, die Immobilie sehr leicht zu halten - selten mehr als ein interner Feldzugang.

Ein Argument für die Verwendung von Eigenschaften besteht darin, dass Sie damit den festgelegten Wert überprüfen können. Ein weiterer Grund ist, dass der Wert der Eigenschaft ein abgeleiteter Wert sein kann und kein einzelnes Feld, wie TotalValue = Betrag * Menge.

Rob Kent
quelle
3

Persönlich verwende ich Eigenschaften nur beim Erstellen einfacher Get / Set-Methoden. Ich weiche davon ab, wenn ich zu komplizierten Datenstrukturen komme.

Steve
quelle
3

Das Argument geht davon aus, dass Eigenschaften schlecht sind, weil sie wie Felder aussehen, aber überraschende Aktionen ausführen können. Diese Annahme wird durch die Erwartungen der .NET-Programmierer ungültig:

Eigenschaften sehen nicht wie Felder aus. Felder sehen aus wie Eigenschaften.

• Eine Eigenschaftsmethode kann eine Ausnahme auslösen. Der Feldzugriff löst niemals eine Ausnahme aus.

Ein Feld ist also wie eine Eigenschaft, die garantiert niemals eine Ausnahme auslöst.

• Eine Eigenschaft kann nicht als out- oder ref-Parameter an eine Methode übergeben werden. ein Feld kann.

Ein Feld ist also wie eine Eigenschaft, verfügt jedoch über zusätzliche Funktionen: Übergabe an eine ref/ outakzeptierende Methode.

• Die Ausführung einer Eigenschaftsmethode kann lange dauern. Der Feldzugriff wird immer sofort abgeschlossen. [...]

Ein Feld ist also wie eine schnelle Eigenschaft.

• Wenn eine Eigenschaftsmethode mehrmals hintereinander aufgerufen wird, kann sie jedes Mal einen anderen Wert zurückgeben. Ein Feld gibt jedes Mal den gleichen Wert zurück. Die System.DateTime-Klasse verfügt über eine schreibgeschützte Now-Eigenschaft, die das aktuelle Datum und die aktuelle Uhrzeit zurückgibt.

Ein Feld ist also wie eine Eigenschaft, die garantiert denselben Wert zurückgibt, es sei denn, das Feld wurde auf einen anderen Wert festgelegt.

• Eine Eigenschaftsmethode kann beobachtbare Nebenwirkungen verursachen. Feldzugriff nie.

Auch hier ist ein Feld eine Eigenschaft, die dies garantiert nicht tut.

• Eine Eigenschaftsmethode erfordert möglicherweise zusätzlichen Speicher oder gibt einen Verweis auf etwas zurück, das nicht Teil des Objektstatus ist. Das Ändern des zurückgegebenen Objekts hat daher keine Auswirkungen auf das ursprüngliche Objekt. Das Abfragen eines Feldes gibt immer einen Verweis auf ein Objekt zurück, das garantiert Teil des ursprünglichen Objektstatus ist. Das Arbeiten mit einer Eigenschaft, die eine Kopie zurückgibt, kann für Entwickler sehr verwirrend sein, und diese Eigenschaft wird häufig nicht dokumentiert.

Dieser mag überraschend sein, aber nicht, weil es eine Eigenschaft ist, die dies tut. Es ist vielmehr so, dass kaum jemand veränderbare Kopien in Eigenschaften zurückgibt, so dass ein Fall von 0,1% überraschend ist.

Milleniumbug
quelle
0

Das Aufrufen von Methoden anstelle von Eigenschaften verringert die Lesbarkeit des aufrufenden Codes erheblich. In J # war die Verwendung von ADO.NET beispielsweise ein Albtraum, da Java keine Eigenschaften und Indexer unterstützt (die im Wesentlichen Eigenschaften mit Argumenten sind). Der resultierende Code war extrem hässlich, mit Methodenaufrufen in leeren Klammern überall.

Die Unterstützung von Eigenschaften und Indexern ist einer der grundlegenden Vorteile von C # gegenüber Java.

Marty Solomon
quelle