// Variante2: special sign casted type with underline
40
private DerivedClassSettings _Settings { get { return (DerivedClassSettings)Settings; } }
41
42
43
//Examples to access settings
44
private bool GetSettingSample1()
45
{
46
return settings.Enabled && settings.Visible;
47
}
48
49
private bool GetSettingSample2()
50
{
51
return _Settings.Enabled && _Settings.Visible;
52
}
53
54
}
55
56
//derived settings type
57
class DerivedClassSettings : BaseClassSettings
58
{
59
public bool Visible { get; set; }
60
}
Wenn ich, wie oben gezeigt...
a) Die Eigenschaft "Settings" sowohl in der abstrakten Basisklasse, als
auch in der Ableitung verwenden möchte.
b) In Abhängigkeit vom Ableitungstyp auch unterschiedliche
Eigenschaftentypen (als Ableitung vom Eigenschaftentyp der Basisklasse)
verwenden möchte.
...muss ich ja in der Ableitung irgendwie casten.
Wie benenne ich denn die Cast-Property?
Wie eine MemberVariable (Variante1) oder zeichne ich die speziell aus
(z.B. durch Unterstrich, wie in Variante2)?
oder macht Ihr das ganz anders?
Warum ist denn die "Settings" Eigenschaft der Basisklasse "public", aber
in der abgeleiteten Klasse "private"? Soll das so?
Falls nicht (und beide Eigenschaften protected oder public sein können),
würde ich die Eigenschaft in der abgeleiteten Klasse genau gleich nennen
wie in der Basisklasse, und sie somit überschreiben (dazu ist scheinbar
noch das Keyword "new" oder "virtual" nötig). So verwendet man
automatisch immer das richtige...
Mit virtual geht's nicht. Da muss die Funktionssignatur (in diesem Fall
der Eigenschaftentyp) identisch sein.
Ha, mit new geht's, sogar mit Interface:
1
interface ILoadableObject
2
{
3
BaseClassSettings Settings{get;}
4
}
5
6
7
//the base class
8
abstract class BaseClass
9
{
10
//Constr.
11
public BaseClass(BaseClassSettings settings)
12
{
13
Settings = settings;
14
}
15
16
//Settings prop
17
public BaseClassSettings Settings { get; private set; }
18
19
20
//Example to access settings
21
public bool GetSettingSample()
22
{
23
return Settings.Enabled;
24
}
25
}
26
27
28
//the base class settings type
29
abstract class BaseClassSettings
30
{
31
public bool Enabled { get; set; }
32
}
33
34
35
// the implementation
36
class DerivedClass : BaseClass, ILoadableObject
37
{
38
//Constr.
39
public DerivedClass(DerivedClassSettings settings) : base(settings) { }
40
41
42
// !!! Hiding Access to base class Setting prop
43
public new DerivedClassSettings Settings
44
{
45
get { return (DerivedClassSettings)base.Settings; }
46
}
47
48
49
//Example to access settings
50
public bool GetSettingSampleDerived()
51
{
52
return Settings.Enabled && Settings.Visible;
53
}
54
}
55
56
//derived settings type
57
class DerivedClassSettings : BaseClassSettings
58
{
59
public DerivedClassSettings(bool visible, bool enabled)
60
{
61
Visible = visible;
62
Enabled = enabled;
63
}
64
public bool Visible { get; set; }
65
}
jo, das klappt, danke.
P.S. Michael. Deine Variante würde die Settings nicht an die Basisklasse
weiterreichen, sondern als Variable in der Ableitung spiegeln?!?
Horst S. schrieb:> P.S. Michael. Deine Variante würde die Settings nicht an die Basisklasse> weiterreichen, sondern als Variable in der Ableitung spiegeln?!?
Der Konstruktor der abgeleiteten Klasse ruft den Konstruktor der
Basisklasse auf und gibt die Settings als Parameter weiter. Somit hat
die Basisklasse eine Referenz auf die Settings vom Typ BaseClassSettings
erhalten.
Hab es jetzt nicht getestet, aber sollte funktionieren
Das klingt irgendwie ziemlich vermurkst ;-)
Wäre es nicht deutlich einfacher zwei verschiedene Eigenschaften zu
verwenden oder ein Interface zu benutzen?
Michael schrieb:> Der Konstruktor der abgeleiteten Klasse ruft den Konstruktor der> Basisklasse auf und gibt die Settings als Parameter weiter. Somit hat> die Basisklasse eine Referenz auf die Settings vom Typ BaseClassSettings> erhalten.>> Hab es jetzt nicht getestet, aber sollte funktionieren
Doch, Du hast recht. Einzig unschön bei Deiner Lösung: Du hast zwei
getrennte Referenzen. Da darf ich dann nie-nie-niemals dem dunklen
Gedanken verfallen, eben mal den Settings 'nen Setter zu verpassen.
Horst S. schrieb:> Doch, Du hast recht. Einzig unschön bei Deiner Lösung: Du hast zwei> getrennte Referenzen. Da darf ich dann nie-nie-niemals dem dunklen> Gedanken verfallen, eben mal den Settings 'nen Setter zu verpassen.
auch das kannst du machen, nur muss der Setter die Referenz der
abgeleiteten Klasse und die Referenz der Basisklasse ändern.
Aus solchen Gründen verwendet man ja Setter. Damit kann man das Ändern
der Referenzen oder Variablen kontrollieren.
1
publicDerivedClassSettingsSettings
2
{
3
set
4
{
5
this.settings=value;
6
base.settings=value;
7
}
8
}
beachte, dass die beiden Referenzen settings nun klein geschrieben sind
(wie man das bei private Variablen und Referenzen so macht), damit
Setter den gleichen Namen, nur groß geschrieben haben darf.
Für mich sieht das auch reichlich undurchsichtig aus.
Kann mir mal jemand der C# Pros die Objektlayouts mitsamt statischen und
dynamischen Typen der Variablen/Referenzen zur Laufzeit der Properties
grob auflisten?
Mich würde die Semantik dahinter und v.a. hinter 'new' interessieren.
In Hoffnung einer Erleuchtung: Danke schon mal.
tk schrieb:> Für mich sieht das auch reichlich undurchsichtig aus.>> Kann mir mal jemand der C# Pros die Objektlayouts mitsamt statischen und> dynamischen Typen der Variablen/Referenzen zur Laufzeit der Properties> grob auflisten?> Mich würde die Semantik dahinter und v.a. hinter 'new' interessieren.>> In Hoffnung einer Erleuchtung: Danke schon mal.
Funktional ist mir das klar. Bei "virtual" testet der Compiler die
Signatur (also Name, Parameter- und Rückgabetypen) der Funktionen in
Basis und Ableitung auf Übereinstimmung. Bei "new" werden gleichnamige
Funktionen mit unterschiedlichen Signaturen durchgelassen (Soweit ich
weiß, ist dann aber die Funktion aus der Basis dann von außen gesehen
endgültig wech, das ist also keine Überladung).
Ob das Schick ist? Ehrliche Antwort? Ich wusste, dass es das
"new"-Schlüsselwort für Funktionen gibt, gebraucht hab ich's in 10
Jahren nicht.
Hier scheint's mal 'nen pragmatischen Ansatz zu bieten, Nicht nur aus
reiner Schreibfaulheit, weil ich keinen Bock habe, in jeder zweiten
Zeile meiner Ableitung die Settings zu casten, sondern auch, weil ich
jetzt wirklich nur die passenden Settings zur Ableitung von außen in das
Objekt stopfen kann.
Ob ich mir allerdings in zwei Jahren aus meinem Code noch klar machen
kann, dass ich durch den Gebrauch des new-Schlüsselwörtchens an dieser
Stelle diese doppeltgeführte Objekthierarchie ("Derived" erbt von "Base"
UND "DerivedSettings" erbt von "BaseSettings") implementiert habe,
naja...
...das gehört wahrscheinlich in den Summaries dokumentiert (aber wer
liest die schon!).
Für den Fall, dass DerivedClassSettings von BaseClassSettings ableitet
(ableiten kann), gibt es noch eine elegante Möglichkeit, die ohne
fehleranfälligen Cast auskommt und die die Typprüfung bereits zur
Compile-Zeit durchführt:
Lol, 'nen Constraint auf'm Generic, da bin ich noch gar nicht drauf
gekommen!
Und natürlich muss DerivedClassSettings von BaseClassSettings erben,
weil ansonsten in BaseClass nix mit den Settings anzustellen wäre.
Mindestens genauso unverständlich für 'nen Youngster zu lesen, wie die
Sache mit dem "new"-Schlüsselwort, aber guter Plan! (Vielleicht sogar
besser wiederzufinden!!!)