Propertys statt Getter und Setter Methoden?



  • SolidOffline schrieb:

    AFAIR ab C# 3.5.

    Ahh... erst in der Zukunft? 😉
    Derzeit aktuell .Net Framework 3.5 und C# 3.0...



  • asc schrieb:

    SolidOffline schrieb:

    AFAIR ab C# 3.5.

    Ahh... erst in der Zukunft? 😉
    Derzeit aktuell .Net Framework 3.5 und C# 3.0...

    Äh, ja richtig, .Net 3.5 hätte es heißen sollen, danke.

    Vielleicht noch ganz interessant in dem Zusammenhang:

    Properties sollte man sowieso nur für triviale Getter/Setter verwenden (einfache Zuweisung), jedenfalls habe ich das mal so irgendwo als Empfehlung in der MSDN gelesen, da die Elementzugriffssyntax (also z.B. myClass.X = 3;) eine einfache Zuweisung mit geringem Performancekostenaufwand suggeriert. Alles was darüber hinausgeht sollte man daher in eigene Funktionen packen, so dass schon anhand der Syntax klar wird, dass das evtl. performancetechnisch mehr kosten könnte. Wobei die Grenze da wohl fließend ist (packe ich x = value * 2 + 4 noch in die Property, oder schon in eine eigene Funktion "SetX"?).



  • SolidOffline schrieb:

    Properties sollte man sowieso nur für triviale Getter/Setter verwenden (einfache Zuweisung), jedenfalls habe ich das mal so irgendwo als Empfehlung in der MSDN gelesen, da die Elementzugriffssyntax (also z.B. myClass.X = 3;) eine einfache Zuweisung mit geringem Performancekostenaufwand suggeriert.

    Wenn trivial in diesem Zusammenhang nur setzen/lesen des Wertes wäre, würde ich (und die Codebeispiele zu WPF) dem widersprechen. Wenn trivial meint, das dort keine Aufwendigen Funktionalitäten enthalten sein sollten, sehe ich das durchaus ähnlich.

    Für mich gehört in die Property:
    a) Setzen/Lesen des Wertes (ggf. indirekt wie bei Proxies)
    b) Wertebereichsprüfungen, sofern diese nicht an einer anderen Stelle sinnvoll sind.
    c) Aufruf von Observern/Changeevents wie z.B. in WPF nicht unüblich.

    cu André



  • asc schrieb:

    Properties halte ich nur aus einen Grund für sinnvoll: Das Sparen von "Get" und "Set", und den Zugriff in Form einer Elementsyntax. Es ist jedenfall (bei nichttrivialen Properties) nicht weniger Schreibaufwand.

    Das geht ja nun am eigentlichen Sinn der Properties so ziemlich vorbei.

    Der eigentliche Vorteil von Properties ist die Persistenz. So funktioniert beispielsweise der Formulardesigner der VCL. Alle Komponenten verfügen über eine Reihe von Properties, die den Status repräsentieren und die im Objektinspektor mittels Reflection angezeigt werden. Wenn eine Komponente auf dem Formular plaziert wird, erstellt der Formulardesigner ein Objekt dieser Komponente im Designer-Modus (die IDE sorgt dafür, daß die Komponente sich auch entsprechend verhält, also nicht wie zur Laufzeit bedienbar ist, sondern z.B. vergrößert, verschoben etc. werden kann). Der Programmierer kann mit Desiger und Objektinspektor über die Properties der Komponente ihren Status festlegen, und beim Speichern wird die Komponente einfach mit den Serialisierungsfunktionen der VCL in die .dfm-Datei gestreamt, die in das Programm als Ressource gelinkt wird. Wird das Programm gestartet, so wird die Komponente aus der .dfm-Datei geladen. So muß der Designer gar nichts weiter über die Komponente wissen: alle nötigen Informationen dafür kann er mittels Reflection erhalten.



  • audacia schrieb:

    Das geht ja nun am eigentlichen Sinn der Properties so ziemlich vorbei.

    Es entspricht so ziemlich den Propertyansatz den ich von Sprachen wie C# gewohnt bin. Es gibt wieder einmal mehrere Definitionen, rein Sprachlich (ohne die IDE-Spezifika zu beachten) ist das für mich nun mal ein Ersatz von Getter und Setter - IDE spezifische Erweiterungen wie in der VCL haben für mich nichts mit dem Begriff Property direkt zu tun, da sie auch anders lösbar sein können (Hier halte ich Konzepte wie Attribute in C# für besser geeignet, die Zusätzliche Informationen bereit stellen).

    cu André



  • asc schrieb:

    Um genau zu sein verwendet C# intern auch nur Getter und Setter, ich glaube get_xxx und set_xxx.

    Klar - INTERN eben! Was denn auch sonst? Ablaufsteuerung via digitaler Heinzelmännchen wäre zwar mal was nettes, aber schwer realisierbar 😃



  • asc schrieb:

    IDE spezifische Erweiterungen wie in der VCL haben für mich nichts mit dem Begriff Property direkt zu tun, da sie auch anders lösbar sein können (Hier halte ich Konzepte wie Attribute in C# für besser geeignet, die Zusätzliche Informationen bereit stellen).

    Wieso soll das ein IDE-spezifisches Feature sein? Das ist ein Sprachmerkmal, von dem die IDE Gebrauch macht.

    Und inwiefern sind Attribute besser für irgendetwas geeignet als Properties? Ich kenne C# und .NET nicht besonders gut, aber das klingt doch sehr nach Äpfeln und Birnen.

    Wenn ich mit dem, was ich von .NET zu wissen glaube, nicht gänzlich daneben liege, dann ist das Property/Reflection-Konzept dort durchaus auch vertreten (und VS macht davon z.B. bei IntelliSense und im Debugger Gebrauch).



  • Ich lese hier immer „Schreibaufwand“. Das ist doch mit Verlaub gesagt riesiger Quatsch. Es geht hier nirgendwo um Schreibaufwand sondern allein um Lesbarkeit.

    Dass Properties lesbarer sind, kann nur ein Blinder bezweifeln.

    obj.x = obj.x * 2 - obj.y;
    // vs.
    obj.setX(obj.getX() * 2 - obj.getY());
    
    return obj.x++;
    
    // vs.
    int ret = obj.getX();
    obj.setX(obj.getX() + 1);
    return ret;
    

    Ach so, übrigens, diese MSDN-Empfehlung, nur für triviale Setter die Property-Syntax zu verwenden, wird ziemlich häufig missverstanden. Es geht dabei lediglich darum, *wirklich* aufwendige Berechnungen auszugrenzen. Niemand erwartet, dass beim Setzen einer Property intern ein TSP ausgeführt wird. Außerdem muss der Status eines Objekts beim mehrfachen Getter-Aufruf konsistent bleiben, es muss z.B. immer derselbe Wert zurückgegeben werden, wenn zwischendurch der Status des Objekts nicht verändert wurden, sonst baut der Compiler durch Optimierungen Mist.

    So. Für C++ ist das natürlich alles irrelevant. Auf CodeProject gab's doch mal einen Code, der über Proxy-Objekte Properties nachgebaut hat. Netter Trick, das Overhead war AFAIR auch gar nicht so hoch … aber das ist doch alles C++-untypisch und daher eher mit Vorsicht zu genießen. Konsistenz ist Trumpf. Wenn die API einheitlich ist, dann sind explizite Getter und Setter gar nicht sooo schlimm.



  • Konrad Rudolph schrieb:

    [...]Auf CodeProject gab's doch mal einen Code, der über Proxy-Objekte Properties nachgebaut hat[...]

    Ich denke mal, Du meinst das hier. Ich finde das aber irgendwie nicht so schön. Echte Properties wären gar nicht so doof. Aber nachbauen würde ich das eher nicht. Das schafft nur Verwirrung (wurde ja hier nun auch schon oft genug gesagt).



  • audacia schrieb:

    asc schrieb:

    IDE spezifische Erweiterungen wie in der VCL haben für mich nichts mit dem Begriff Property direkt zu tun, da sie auch anders lösbar sein können (Hier halte ich Konzepte wie Attribute in C# für besser geeignet, die Zusätzliche Informationen bereit stellen).

    Wieso soll das ein IDE-spezifisches Feature sein? Das ist ein Sprachmerkmal, von dem die IDE Gebrauch macht.

    Es ist eben kein Sprachmerkmal - zumindestens keines des Sprachstandards.

    Es geht mir nicht darum ob die VCL Properties sinnvoll sind oder nicht (in Zusammenhang mit der VCL, die ich derzeit auch wieder Verwende halte ich sie - bei den Komponenten - für sinnvoll), aber ich mag vermeide jegliche Konstrukte die nicht von der Sprache selbst abgedeckt werden, wo ich nur kann. Es mag zwar sein das keine Migration geplant ist, aber ich halte dennoch gerne die Wege offen für Frameworkwechsel (aus gemachter Erfahrung).

    audacia schrieb:

    Und inwiefern sind Attribute besser für irgendetwas geeignet als Properties? Ich kenne C# und .NET nicht besonders gut, aber das klingt doch sehr nach Äpfeln und Birnen.

    Du bist imho der erste in diesen Thread der die Auffassung hat das Properties mehr als Getter und Setter sind. Attribute in C# können Sprachbestandteile ergänzen ohne Inhaltlich etwas zu ändern. Ich habe hier die Syntax nicht im Kopf aber es sieht in etwa so aus:

    // Ohne Syntaxkorrektheit nur als grobes Beispiel:
    // Fall 1: "Normale" Property
    class MyClass {
      public int X { get; set; }
      private int y;
    } 
    
    // Fall 2: Wir ergänzen um einen Attribut
    [Serializable]
    class MyClass {
      public int X { get; set; }
    
      [NonSerialized]
      private int y;
    }
    

    audacia schrieb:

    Wenn ich mit dem, was ich von .NET zu wissen glaube, nicht gänzlich daneben liege, dann ist das Property/Reflection-Konzept dort durchaus auch vertreten (und VS macht davon z.B. bei IntelliSense und im Debugger Gebrauch).

    Ja, ist es. Wobei die Verwendung weit über IntelliSense und Debugger hinaus geht. Zum Beispiel für die von dir erwähnte Serialisierung. Was ich prinzipiel besser finde ist die Tatsache das es leichter anzupassen und zu ergänzen ist.

    Wir müssen aber nicht so sehr auf den Begrifflichkeiten rumhacken: Für mich ist eine Property halt Getter und Setter, für dich hat sie zudem noch weitere (Frameworkspezifische) Bedeutungen. Dies Ändert nichts an der grundlegenden Idee dahinter.

    cu André



  • Tachyon schrieb:

    Konrad Rudolph schrieb:

    [...]Auf CodeProject gab's doch mal einen Code, der über Proxy-Objekte Properties nachgebaut hat[...]

    Ich denke mal, Du meinst das hier.

    Nein, ich meinte eine Lösung ohne Macros. Ist aber auch egal, es ging eigentlich nur um die prinzipielle Machbarkeit – in jedem Fall aber per Workaround.



  • asc schrieb:

    SolidOffline schrieb:

    Properties sollte man sowieso nur für triviale Getter/Setter verwenden (einfache Zuweisung), jedenfalls habe ich das mal so irgendwo als Empfehlung in der MSDN gelesen, da die Elementzugriffssyntax (also z.B. myClass.X = 3;) eine einfache Zuweisung mit geringem Performancekostenaufwand suggeriert.

    Wenn trivial in diesem Zusammenhang nur setzen/lesen des Wertes wäre, würde ich (und die Codebeispiele zu WPF) dem widersprechen. Wenn trivial meint, das dort keine Aufwendigen Funktionalitäten enthalten sein sollten, sehe ich das durchaus ähnlich.

    Für mich gehört in die Property:
    a) Setzen/Lesen des Wertes (ggf. indirekt wie bei Proxies)
    b) Wertebereichsprüfungen, sofern diese nicht an einer anderen Stelle sinnvoll sind.
    c) Aufruf von Observern/Changeevents wie z.B. in WPF nicht unüblich.

    cu André

    Käme nach meinem Verständnis darauf an, ob bei Benutzung der Property klar ist, dass damit evtl. höhere "Kosten" verbunden sind. Die oben genannten Punkte können doch durchaus schon in den Bereich "aufwändige Funktionalitäten" fallen, im Vergleich zu einem bloßen Setzen einer Membervariablen.

    Ich denke mal, man wird es nicht pauschal festlegen können, sollte es aber immer im Hinterkopf haben und sich konkret überlegen, ob nicht evtl. eine eigene Funktion - z.B. ChangeX() oder UpdateX() - besser (im Sinne der "Kosten-Offenlegung") wäre. Denn in einer inneren Schleife 100.000 mal "myClass.X = i;" kann sonst unerwartet "teuer" werden. 😉



  • Konrad Rudolph schrieb:

    [...]
    Ach so, übrigens, diese MSDN-Empfehlung, nur für triviale Setter die Property-Syntax zu verwenden, wird ziemlich häufig missverstanden. Es geht dabei lediglich darum, *wirklich* aufwendige Berechnungen auszugrenzen. Niemand erwartet, dass beim Setzen einer Property intern ein TSP ausgeführt wird.
    [...]

    Die Frage ist: ab wann wird es *wirklich* aufwändig. Wie in einem Posting zuvor erläutert, richtet man sich wohl am besten danach, ob bei Benutzung der Property klar ist, dass da evtl. noch einiges mehr geschieht, als das bloße Setzen der Membervariablen. Wie gesagt: 100.000 x "myClass.X = i" kann auch *wirklich* aufwändig werden, wenn ich nicht damit rechne (oder nicht mehr daran denke), dass da evtl. mehr drinsteckt als es den Anschein hat. 😉

    Aber ihr habt schon recht: so ganz wörtlich sollte man die Empfehlung dann doch nicht nehmen. 🙂



  • SolidOffline schrieb:

    Aber ihr habt schon recht: so ganz wörtlich sollte man die Empfehlung dann doch nicht nehmen. 🙂

    Die Empfehlung ist schon okay, sofern die Beispiele in der MSDN auch in Ordnung sind (Weil gerade in WPF ist es nicht unüblich das dort noch Aufrufe für die Observer enthalten sind; Zudem behaupte ich mal das Bereichsprüfungen auch in mindestens einem Beispiel enthalten sind, ohne hierfür konkret nachzuschauen).

    cu André



  • asc schrieb:

    Es ist eben kein Sprachmerkmal - zumindestens keines des Sprachstandards.

    So what? Dafür ist es eines in Delphi, C#, C++Builder etc. pp. Mein Punkt war, daß es kein Vorzug der IDE, sondern ein intrinsische Eigenschaft der Sprache ist.

    asc schrieb:

    Du bist imho der erste in diesen Thread der die Auffassung hat das Properties mehr als Getter und Setter sind.

    Das ist natürlich auch ein Argument.

    asc schrieb:

    Attribute in C# können Sprachbestandteile ergänzen ohne Inhaltlich etwas zu ändern.
    ...

    Ja, was Attribute sind, weiß ich 😉

    asc schrieb:

    Wir müssen aber nicht so sehr auf den Begrifflichkeiten rumhacken: Für mich ist eine Property halt Getter und Setter, für dich hat sie zudem noch weitere (Frameworkspezifische) Bedeutungen. Dies Ändert nichts an der grundlegenden Idee dahinter.

    Ist es nicht "die grundlegende Idee dahinter", die wir da diskutieren, also die Motivation, überhaupt so etwas wie Properties in eine Sprache einzuführen?

    Jedenfalls wäre ich interessiert, wie du ohne Properties ein Objekt serialisieren und über so etwas wie einen Objektinspektor modifizierbar machen willst. Wenn du da nur Getter und Setter benutzt, mußt du z.B. mindestens eine Konvention für deren Benennung erzwingen, so daß z.B. für ein Pseudoproperty "Height" Getter und Setter getHeight und setHeight heißen müßten; das resultiert in einer Inkonsistenz zwischen der Verwendung im Code und der Anzeige des Objektinspektors. Das ist mindestens unschön. Und wie wolltest du die Pseudoproperties mit Attributen versehen, z.B. (analog zu Delphi) default/nodefault, stored, index, oder was .NET so zu bieten hat?



  • audacia schrieb:

    Jedenfalls wäre ich interessiert, wie du ohne Properties ein Objekt serialisieren und über so etwas wie einen Objektinspektor modifizierbar machen willst. Wenn du da nur Getter und Setter benutzt, mußt du z.B. mindestens eine Konvention für deren Benennung erzwingen

    Ja. Und was spricht dagegen? Machen Java Beans doch auch. Man könnte auch, wie von Dir vorgeschlagen, Annotationen/Attribute verwenden. Alles kein Ding. Solange das Serialisierungs- bzw. Introspektionsframework diese Konvention kennt, ist alles machbar. Und das muss ja nicht zwingend Bestandteil der Sprache sein sondern kann eine freie Bibliothek oder gar ein vollkommen separates Tool (wie Google das mit den Protocol Buffers tut) sein.



  • Konrad Rudolph schrieb:

    Machen Java Beans doch auch.

    IMHO schon ein Argument dagegen. SCNR 😉

    Konrad Rudolph schrieb:

    Man könnte auch, wie von Dir vorgeschlagen, Annotationen/Attribute verwenden. Alles kein Ding.

    Wer bekommt die Attribute? Getter, Setter, beide? Falls letzteres, wie wird mit Redundanz und mit widersprüchlichen Attributen umgegangen? Falls nur einer, welcher?



  • audacia schrieb:

    Konrad Rudolph schrieb:

    Machen Java Beans doch auch.

    IMHO schon ein Argument dagegen. SCNR 😉

    Hehe. Mag sein. Ich bevorzuge ja auch Properties.

    Konrad Rudolph schrieb:

    Man könnte auch, wie von Dir vorgeschlagen, Annotationen/Attribute verwenden. Alles kein Ding.

    Wer bekommt die Attribute? Getter, Setter, beide? Falls letzteres, wie wird mit Redundanz und mit widersprüchlichen Attributen umgegangen? Falls nur einer, welcher?

    Das sind natürlich alles gute Einwände. Wer ein entsprechendes Framwework bastelt, muss sich das gut überlegen. Ich habe keine pauschale Antwort darauf. Ich würde allerdings mal sagen, wenn man Annotations verwendet, dann müssen beide Methoden sowas erhalten (schon deswegen, weil man sonst gleich Namenskonventionen verwenden könnte, und auch, um Properties selektiv read-only zu machen). Man könnte sogar noch einen Schritt weitergehen und ganz andere Konventionen finden, z.B. (in Java) anonyme, verschachtelte Klassen, die von einem „Property“-Interface hergeleitet sind:

    interface ReadOnlyProperty<T> {
        public T get();
    }
    
    interface Property<T> extends ReadOnlyProperty<T> {
        public void set(T value);
    }
    
    class Foo {
        private int _x;
    
        public final Property<Integer> X = new Property<Integer>() {
            public Integer get() { return _x; }
            void set(Integer value) { _x = value; }
        };
    }
    
    Foo f = new Foo();
    f.X.set(42);
    System.out.println(f.X.get());
    

    Ungetestet, so in der Art sollte das aber gehen und ich bin sicher nicht der erste, der auf diesen Trichter kommt.

    /EDIT: getestet, korrigiert, klappt. Hui. Das lasse ich mir patentieren. 😉



  • Und in C++ kann man Properties gut mit Template-Klassen nachbauen:

    // property.h
    
    #ifndef PROPERTY_H
    #define PROPERTY_H
    
    template<typename T> class property_wrapper
    {
    public:
    	explicit property_wrapper(const T& t)
    		: _t(t)
    	{}
    
    	operator T() const { return _t; }
    
    private:
    	const T& _t;
    };
    
    template<typename T> class property_readonly
    {
    public:
    	property_readonly()
    	{}
    	property_readonly(const T& t)
    		: _t(t)
    	{}
    
    	const T& get() const { return _t; }
    
    	const T& operator () () const { return _t; }
    
    	operator T() const { return _t; }
    
    	T& operator = (const property_wrapper<T>& t) { return _t = t; }
    
    protected:
    	void set(const T& t) { _t = t; }
    
    	const T& operator = (const T& t) { _t = t; return t; }
    	const T& operator ()(const T& t) { _t = t; return t; }
    
    	const T& operator += (const T& t) { _t += t; return _t; }
    	const T& operator -= (const T& t) { _t -= t; return _t; }
    
    private:
    	T _t;
    };
    
    template<typename T> class property
    {
    public:
    	property()
    	{}
    	property(const T& t)
    		: _t(t)
    	{}
    
    	const T& get() const { return _t; }
    	void set(const T& t) { _t = t; }
    
    	const T& operator = (const T& t) { _t = t; return t; }
    	const T& operator += (const T& t) { _t += t; return _t; }
    	const T& operator -= (const T& t) { _t -= t; return _t; }
    
    	const T& operator () () const { return _t; }
    	const T& operator () (const T& t) { _t = t; return t; }
    
    	operator T() const { return _t; }
    
    private:
    	T _t;
    };
    
    #endif
    

    Und die Benutzung dann z.B. so:

    void TestProperty()
    {
    	class PropTest
    	{
    	public:
    		PropTest()
    			: x(0), y(0)
    		{}
    
    		void set_y(int value)
    		{
    			y = property_wrapper<int>(value); // only set property with wrapper class
    		}
    
    		property<int> x;
    		property_readonly<int> y;
    	};
    
    	PropTest p;
    
    	p.x.set(0);
    	//p.y.set(1);
    	int x = p.x.get();
    	int y = p.y.get();
    
    	p.x(42);
    	x = p.x();
    
    	p.x = 14;
    	x = p.x;
    	p.x = x;
    
    	//p.y = 13; // no access to protected member
    	//p.y(7);	// same error -> OK
    	p.set_y(7);
    	y = p.y;
    	p.set_y(y);
    }
    

    Ich habe auch noch eine Variante, bei der man die Getter- und Setter-Methode explizit angeben kann...



  • Konrad Rudolph schrieb:

    Das sind natürlich alles gute Einwände. Wer ein entsprechendes Framwework bastelt, muss sich das gut überlegen. Ich habe keine pauschale Antwort darauf. Ich würde allerdings mal sagen, wenn man Annotations verwendet, dann müssen beide Methoden sowas erhalten (schon deswegen, weil man sonst gleich Namenskonventionen verwenden könnte, und auch, um Properties selektiv read-only zu machen).

    Das ist alles schön und gut, führt uns aber nur wieder zurück zu meinem Punkt: der Motivation, so etwas wie Properties in eine Sprache einzuführen. Neben dem Vorteil in der Lesbarkeit, den du ja zu Recht hervorhebst, hat man mit dem Sprachmittel der Properties eine eindeutige, leicht verständliche, redundanzfreie, nicht konventionsbindende Syntax, mittels derer man den Status eines Objektes repräsentieren kann; dies ist meines Wissens der Anlaß für die Einführung von Properties in Delphi gewesen. Daß es etwas schöner aussieht als Getter und Setter, ist ein legitimes Argument für Ästheten (und Sprachdesigner sollten einen Sinn für so etwas haben!), aber es ist nicht das Wesentliche.


Anmelden zum Antworten