2010-05-25 11 views
19

Mögliche Duplizieren nicht tun:
Convention question: When do you use a Getter/Setter function rather than using a PropertyWas Getter und Setter sollte und

Ich habe in letzter Zeit mit unterschiedlichen Meinungen zu Getter und Setter in eine Menge laufen, so dachte ich, Ich sollte es in seine eigene Frage bringen.

Eine previous question von mir erhielt einen sofortigen Kommentar (später gelöscht), dass Setzer sollten keine Nebenwirkungen haben, und eine SetProperty Methode wäre eine bessere Wahl.

Tatsächlich scheint dies auch Microsoft's opinion zu sein. Ihre Eigenschaften führen jedoch häufig zu Ereignissen wie Resized, wenn die Eigenschaft Width oder Height eines Formulars festgelegt ist. OwenP besagt auch "Sie sollten nicht zulassen, dass eine Eigenschaft Ausnahmen auslöst, Eigenschaften sollten keine Nebenwirkungen haben, Reihenfolge sollte nicht wichtig sein, und Eigenschaften sollten relativ schnell zurückkehren."

Noch Michael Stum besagt, dass beim Validieren von Daten in einem Setter Ausnahmen ausgelöst werden sollten. Wenn Ihr Setter keine Ausnahme auslöst, wie können Sie effektiv Daten validieren, wie so viele der Antworten auf this question vorschlagen?

Was ist, wenn Sie ein Ereignis auslösen müssen, wie fast alle von Microsoft's Control tun? Sind Sie dann nicht der Gnade von wem auch immer Ihre Veranstaltung abonniert? Wenn ihr Handler eine große Menge an Informationen ausführt oder selbst einen Fehler auslöst, was passiert dann mit Ihrem Setter?

Schließlich, was ist mit lazy loading im Getter? Auch dies könnte gegen die vorherigen Richtlinien verstoßen.

Was ist akzeptabel, um in einem Getter oder Setter zu platzieren, und was sollte nur in Accessor-Methoden aufbewahrt werden?

Edit:

Von einer anderen article in der MSDN:

Die get und set Methoden sind in der Regel nicht von anderen Methoden. Sie können jede Programmlogik ausführen, Ausnahmen auslösen, überschrieben werden und mit beliebigen von der Programmiersprache erlaubten Modifikatoren deklariert werden. Beachten Sie jedoch, dass Eigenschaften auch statisch sein können. Wenn eine Eigenschaft statisch ist, gibt es Einschränkungen, was die Methoden get und set können. Weitere Informationen finden Sie in Ihrer Programmiersprache.

+0

Ich las diese Frage, die Antworten und sogar damit in meiner eigenen Frage verknüpft. Ich habe nichts über Veranstaltungen gesehen, was meiner Meinung nach andere Antworten verdient. – dlras2

+1

@Rowland: Ich denke, es ist spezifisch genug, um anders zu sein. –

+2

Wer hat dafür gestimmt, dass er zum Super User migriert wird? – ChrisF

Antwort

15

Meine Ansicht:

  1. Wenn ein Setter oder Getter wird erwartet, teuer zu sein, sollten Sie es nicht eine Eigenschaft machen, ist es ein Verfahren machen.

  2. Wenn das Festlegen einer Eigenschaft Ereignisse aufgrund von Änderungen auslöst, ist dies in Ordnung. Wie sonst würden Sie den Zuhörern erlauben, über Änderungen informiert zu werden? Möglicherweise möchten Sie jedoch ein BeginInit/EndInit-Paar anbieten, um Ereignisse zu unterdrücken, bis alle Änderungen vorgenommen wurden. In der Regel liegt es in der Verantwortung des Event-Handlers, umgehend zurückzukommen, aber wenn Sie ihm wirklich nicht vertrauen können, dann möchten Sie vielleicht das Ereignis in einem anderen Thread signalisieren.

  3. Wenn das Festlegen einer Eigenschaft Ausnahmen für ungültige Werte auslöst, ist es auch in Ordnung. Dies ist ein sinnvoller Weg, um das Problem zu signalisieren, wenn der Wert komplett falsch ist. In anderen Fällen legen Sie eine Reihe von Eigenschaften fest und rufen dann eine Methode auf, die diese verwendet, um beispielsweise eine Verbindung herzustellen. Dies würde Validierungen und Fehlerbehandlungen verhindern, bis die Eigenschaften verwendet werden, sodass die Eigenschaften nichts mehr werfen müssen.

  4. Der Zugriff auf eine Eigenschaft kann Nebenwirkungen haben, solange sie nicht unerwartet sind und keine Rolle spielen. Dies bedeutet, dass eine JIT-Instanziierung in einem Getter in Ordnung ist. Das Setzen eines schmutzigen Flags für die Instanz, wenn eine Änderung vorgenommen wird, ist genauso gut, wenn Sie eine verwandte Eigenschaft wie ein anderes Format für denselben Wert festlegen.

  5. Wenn es etwas tut im Gegensatz zum Zugriff nur auf einen Wert, sollte es eine Methode sein. Methode sind Verben. Daher würde das Erstellen einer Verbindung von der OpenConnection() - Methode und nicht von einer Connection-Eigenschaft erfolgen. Eine Verbindungseigenschaft würde verwendet, um die verwendete Verbindung abzurufen oder um die Instanz an eine andere Verbindung zu binden.

bearbeiten - hinzugefügt 5, geändert 2 und 3

1

ich mit dem Gedanken zustimmen, dass Getter/Einstellungen keine Nebenwirkungen haben sollte, aber ich würde sagen, dass sie nicht nicht haben sollte, offensichtliche Nebenwirkungen.

Bis zum Auslösen von Ausnahmen, wenn Sie eine Eigenschaft auf einen ungültigen Wert setzen (in einem sehr grundlegenden Sinne), dann Validierung Ausnahmen sind in Ordnung. Wenn der Setter jedoch eine ganze Reihe komplizierter Geschäftsregelüberprüfungen ausführt oder versucht, andere Objekte oder andere Objekte, die eine Ausnahme verursachen könnten, zu aktualisieren, ist das schlecht. Aber dieses Problem ist nicht wirklich ein Problem mit der Ausnahme selbst, sondern eher, dass der Setter abgeht und heimlich eine Menge von Funktionen ausführt, die der Anrufer nicht erwarten würde (oder sollte).

Das gleiche mit Ereignissen. Wenn ein Setter ein Ereignis wirft, dass "diese Eigenschaft geändert" ist, dann ist es in Ordnung, denn das ist ein offensichtlicher Nebeneffekt. Aber wenn es ein anderes benutzerdefiniertes Ereignis auslöst, so dass ein versteckter Code in einem anderen Teil eines Systems ausgeführt wird, ist es schlecht.

Dies ist der gleiche Grund, warum ich lazy-loading in getters vermeiden. In der Tat können sie die Dinge viel einfacher machen, aber sie können die Dinge manchmal etwas verwirrender machen, weil es immer eine verworrene Logik gibt, genau dann, wenn Sie möchten, dass die untergeordneten Objekte geladen werden. Es ist normalerweise nur eine weitere Codezeile, um die untergeordneten Objekte explizit zu laden, wenn Sie das übergeordnete Objekt auffüllen, und es kann viel Verwirrung über den Objektstatus vermieden werden. Aber dieser Aspekt kann sehr subjektiv werden, und vieles hängt von der Situation ab.

+0

Die Vermeidung von Faulheit kann erhebliche Leistungskosten verursachen, daher halte ich das im Allgemeinen nicht für eine gute Idee. –

+1

@Steven Sundit: Ja, es ist ein Kompromiss, und es hängt von der Situation ab. Wenn das Vorladen substantielle Leistungskosten mit sich bringt, dann sollte das Lazy Loading oder das situationsspezifische Laden fortgesetzt werden. Aber oft (und meiner Erfahrung nach normalerweise) ist das nicht der Fall. –

+0

Das Vorladen kann sicherlich eine geeignete Wahl sein, besonders wenn es entweder billig oder einmalig ist. Wenn es keiner von beiden ist, wird JIT zu einem erzwungenen Zug. –

0

Ich habe immer den konservativen Ansatz gefunden, der am besten ist, wenn man in C# sowieso arbeitet. Da Eigenschaften syntaktisch mit Feldern identisch sind, sollten sie wie Felder funktionieren: keine Ausnahmen, keine Validierung, keine witzige Angelegenheit. (Tatsächlich beginnen die meisten meiner Objekte als einfache Felder und werden erst dann zu Eigenschaften, wenn sie absolut notwendig sind.) Die Idee ist, dass wenn man etwas sieht, das aussieht oder ein Feld setzt, dann ist es so etwas wie bekommen oder Setzen eines Feldes in Bezug auf die Funktionalität (es gibt keine Ausnahme), Gesamteffizienz (das Setzen von Variablen löst keine Kaskade von Delegiertenaufrufen aus) und Auswirkungen auf den Programmzustand (das Setzen einer Variablen setzt diese Variable und t rufen viele Delegierte, die fast alles tun könnten).

Sensible Dinge für eine Unterkunft zählen zu tun, ein Flag, um anzuzeigen, dass es eine Änderung gewesen:

set { 
    if(this.value!=value) { 
     this.changed=true; 
     this.value=value; 
    } 
} 

Vielleicht tatsächlich Wert auf ein anderes Objekt gesetzt, zum Beispiel:

set { this.otherObject.value=value; } 

Vielleicht entwirren Sie den Eingang ein wenig, um den internen Code der Klasse zu vereinfachen:

set { 
    this.isValid=(value&Flags.IsValid)!=0; 
    this.setting=value&Flags.SettingMask; 
} 

(O In den letzten beiden Fällen könnte die get-Funktion das Gegenteil bewirken.

Wenn etwas Komplizierteres passieren muss, insbesondere Delegaten aufrufen oder Validierung durchführen oder Ausnahmen auslösen, dann ist meine Ansicht, dass a Funktion ist besser. (Sehr oft werden meine Felder zu Eigenschaften mit get und set und enden dann als get-Eigenschaft und set-Funktion.) Ähnlich für die Getter; Wenn Sie einen Verweis auf etwas zurückgeben, ist das kein Problem, aber wenn Sie ein neues großes Objekt erstellen und es jedes Mal ausfüllen, wenn die Eigenschaft gelesen wird - nicht so heiß.

+0

Wenn Sie in C# arbeiten, müssen Sie auf WPF achten, das vollständig von Eigenschaftsänderungen abhängt, die den Nebeneffekt haben, diese Änderungen zu signalisieren. Ich sehe nicht, wie wir Ihrem Rat folgen können, ohne unseren Code zu lähmen. –

+0

Wenn Sie "den Nebeneffekt des Signalisierens dieser Änderungen" sagen, beziehen Sie sich auf das Auslösen eines Ereignisses? Oder sagst du, wenn '(this.value! = Value) zurückkehrt;' wäre eine schlechte Idee? Ich habe nicht mit WPF gearbeitet. (Tho ich programmiere in C#.) – dlras2

+0

@Cyclosis: Nun, das gilt für mehr als nur WPF, aber WPF macht besonders deutliche Verwendung von Benachrichtigung über die Änderung von Eigenschaften. An vielen Stellen, an denen die Datenbindung verwendet wird, finden Sie auch Beispiele. Wenn wir nicht zulassen, dass Ereignisse ausgelöst werden, wenn sich etwas ändert, was haben wir dann? Umfrage? –