Forum: PC-Programmierung C# Benennung gecasteter Eigenschaft


von Horst S. (Gast)


Lesenswert?

1
 //the base class
2
    abstract class BaseClass
3
    {
4
        //Constr.
5
        public BaseClass(BaseClassSettings settings)
6
        {
7
            Settings = settings;
8
        }
9
10
        //Settings prop
11
        public BaseClassSettings Settings { get; set; }
12
13
14
        //Example to access settings
15
        private bool GetSettingSample()
16
        {
17
            return Settings.Enabled;   
18
        }
19
    }
20
21
22
    //the base class settings type
23
    abstract class BaseClassSettings
24
    {
25
        public bool Enabled { get; set; }
26
    }
27
28
29
    // the implementation
30
    class DerivedClass : BaseClass
31
    {
32
        //Constr.
33
        public DerivedClass(DerivedClassSettings settings) : base(settings) { }
34
35
36
        // Variante1: name casted setting as member
37
        private DerivedClassSettings settings{get{return (DerivedClassSettings) Settings; }}
38
        
39
        // 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?

von Dr. Sommer (Gast)


Lesenswert?

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...

von Michael (Gast)


Lesenswert?

ich bin mir zwar nicht sicher, ob ich verstehe worauf du hinaus willst, 
aber versuchs mal damit:
1
class DerivedClass : BaseClass
2
{
3
    //Constr.
4
    public DerivedClass(DerivedClassSettings settings) : base(settings)
5
    {
6
        Settings = settings;
7
    }
8
9
    // Variante1: name casted setting as member
10
    private new DerivedClassSettings Settings;
11
12
    //Examples to access settings
13
    private bool GetSettingSample1()
14
    {
15
        return Settings.Enabled && Settings.Visible;
16
    }
17
}

von Horst S. (Gast)


Lesenswert?

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?!?

von Michael (Gast)


Lesenswert?

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

von Borislav B. (boris_b)


Lesenswert?

Das klingt irgendwie ziemlich vermurkst ;-)

Wäre es nicht deutlich einfacher zwei verschiedene Eigenschaften zu 
verwenden oder ein Interface zu benutzen?

von Horst S. (Gast)


Lesenswert?

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.

von Michael (Gast)


Lesenswert?

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
public DerivedClassSettings Settings
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.

von Horst S. (Gast)


Lesenswert?

Dann kann ich's allerdings auch gleich, wie oben, als Verweis auf die 
Basisreferenz mit Casting betreiben.
1
        public new DerivedClassSettings Settings 
2
        { 
3
            get { return (DerivedClassSettings)base.Settings; }
4
            set { base.Settings = value;}
5
        }

von tk (Gast)


Lesenswert?

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.

von Horst S. (Gast)


Lesenswert?

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!).

von Markus (Gast)


Lesenswert?

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:
1
using System;
2
3
public class BaseClassSettings
4
{
5
    public bool Enabled { get; set; }
6
}
7
8
public class DerivedClassSettings
9
    : BaseClassSettings
10
{
11
    public int Value { get; set; }
12
}
13
14
public abstract class BaseClass<TSettings>
15
    where TSettings : BaseClassSettings
16
{
17
    public BaseClass()
18
    {
19
    }
20
21
    public TSettings Settings { get; set; }
22
23
    private bool GetSettingSample()
24
    {
25
        return Settings.Enabled;
26
    }
27
}
28
29
public class DerivedClass
30
    : BaseClass<DerivedClassSettings>
31
{
32
    private void SettingsTest()
33
    {
34
        Console.WriteLine("BaseClassSetting.Enabled: {0}", Settings.Enabled);
35
        Console.WriteLine("DerivedClassSetting.Value: {0}", Settings.Value);
36
    }
37
}

Grüße
Markus

von Horst S. (Gast)


Lesenswert?

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!!!)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.