[C#] Constanten uit subclassen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • dtech
  • Registratie: Juni 2005
  • Laatst online: 13-06 23:19
Beste GoT'ters,

ik heb een probleempje. Ik wil in een virtuele methode uit een basisklasse constanten uit een subklasse gebruiken. Ik kan het probleem zo versimpel weergeven:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Override
{
    public /* iets */ print = "Base";
    public virtual void Print()
    {
        Console.WriteLine(print);
    }
}

class Subclass : Override
{
    public /* iets */ print = "Sub";

    static public void Main(string[] args)
    {
        Subclass a = new Subclass();
        a.Print(); // Verwacht: "Sub"
        Override b = new Subclass();
        b.Print(); // Verwacht: "Sub"
        Override c = new Override();
        c.Print(); // Verwacht: "Base"
    }
}


Maar wat ik ook probeer, ik krijg altijd "Base". Dit is wat ik al geprobeerd heb:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
// Base class:
public const String t1 = "Base";
public const String t2 = "Base";
public readonly String t3 = "Base";
public static readonly String t4 = "Base";
public static readonly String t5 = "Base";

// Subclass:
public const String t1 = "Sub";
public new const String t2 = "Sub";
public readonly String t3 = "Sub";
public static readonly String t4 = "Sub";
public new static readonly String t5 = "Sub";


Maar met alles krijg ik dus "Base".

Weet iemand hoe het wel moet?

[ Voor 2% gewijzigd door dtech op 15-05-2010 22:42 . Reden: linkje toegevoegd ]


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 12-09 06:48

Sebazzz

3dp

Dat is niet meer dan logisch. Static fields erfen bij definitie niet over.
Vergeet niet dat je bij regel 6 impliciet naar Override.print refereert, niet naar (mijnTypeOfSubclass).print. Er is geen garantie dat de subclass print bevat.

Wat wil je, misschien probeer je een probleem op een foute manier op te lossen?

Je kan het overigens wel doen zoals je wilt, maar dan met Reflection. Of je maakt een property, die niet static is. De semantiek is wel wat anders dan. Bijvoorbeeld:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Base {
    protected virtual string SomeConstant {
          get { return "Base class zegt hoi"; }
    }
    
    public void PrintConstant() {
          Console.WriteLine(this.SomeConstant);
    }
}

class Sub : Base {
    protected override string SomeConstant {
          get { return "Sub class zegt hoi"; }
    }
}

class Program {
    void Main() {
        Base b = new Base();
        b.PrintConstant(); // Base class zegt hoi
        
        Sub s = new Sub();
        s.PrintConstant(); // Sub class zegt hoi

        Base boxed = new Sub();
        boxed.PrintConstant(); // Sub class zegt hoi
    }
}

[ Voor 70% gewijzigd door Sebazzz op 15-05-2010 22:50 ]

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • dtech
  • Registratie: Juni 2005
  • Laatst online: 13-06 23:19
Die propertie is wel een goede.

Ik wil het gebruiken voor een paar simpele SQL klassen. Een basisklas kan een aantal methoden specificeren die enkel met SQL tabel verschillen. Je krijgt dan zo iets:
code:
1
2
3
4
5
6
7
class DatabaseObject{
public void Delete(){
    // table is de constante:
    String sql = "DELETE FROM " + table + " WHERE id = " + this.id;
    // Rest van het SQL spul
}
}


Is er een betere manier hiervoor dan?

Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 12-09 06:48

Sebazzz

3dp

Een property zoals ik voorstelde, of je zet in de constructor van de base class het protected field, maar protected fields gaan zowieso tegen de richtlijnen in (detail, maar toch). Zoiets:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Base {
    protected readonly string Hoi;
    
    public Base() {
        Hoi = "Hey!";
    }
    
    protected Base(string constant) { /** Protected constructor, zo kan het readonly field worden geset in de base class maar niet buiten de class **/
        Hoi = constant;
    }
    
    public void Print() {
        Console.WriteLine(Hoi);
    }
}

class Sub : Base {
    public Sub() : base("Haai") { }
}
    

[ Voor 10% gewijzigd door Sebazzz op 15-05-2010 23:00 ]

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • dtech
  • Registratie: Juni 2005
  • Laatst online: 13-06 23:19
Sebazzz schreef op zaterdag 15 mei 2010 @ 22:59:
maar protected fields gaan zowieso tegen de richtlijnen in (detail, maar toch).
Hoezo? Protected constructors vind ik (precies voor dit soort situaties, waarin subclassen bepaalde grapjes uit moeten kunnen halen) verder geen probleem.

Dat veld met de readonly vind ik ook wel mooi, maar ik ga denk ik met de properties.

Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 12-09 06:48

Sebazzz

3dp

dtech schreef op zaterdag 15 mei 2010 @ 23:04:
[...]


Hoezo? Protected constructors vind ik (precies voor dit soort situaties, waarin subclassen bepaalde grapjes uit moeten kunnen halen) verder geen probleem.

Dat veld met de readonly vind ik ook wel mooi, maar ik ga denk ik met de properties.
Protected constructors zijn niet tegen de richtlijnen, protected fields wel. Richtlijnen dicteren grofweg dat alles wat exposed wordt naar de buitenwereld (vanaf een class gezien) een property of een constant (const) moet zijn. Maar het zijn richtlijnen, geen wetboek. Je zou de readonly field private kunnen maken en naar afleidende classes als property exposen.
C#:
1
2
3
4
class Base {
    private readonly string hoi;
    protected string Hoi { get { return this.hoi; } }
}


Er valt nog wel iets op te merken, als het type dat je 'constant' of onveranderd wil hebben een primitive is zoals een string of een integer en je wilt dat het blijft zoals het is, moet je voor de laatstgenoemde oplossing gaan.
Bij de eerste oplossing met de property, is de afgeleide class vrij om een willekeurige waarde door te geven.

C#:
1
2
3
4
5
6
7
8
9
class Sub : Base {
    public Sub() : base("Haai") { } // Haai blijft haai
}

class Sub : Base {
    protected override string SomeConstant {
          get { return new Random().Next().ToString(); } // kan verschillende waardes terug geven
    }
} 

[ Voor 5% gewijzigd door Sebazzz op 15-05-2010 23:58 ]

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

Hou alstublieft die queries uit je business objects. Die hebben geen nut daar.
Mapping van objecten op tabellen doe je liever buiten je business objects. Ander voorbeeldje:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
abstract class DBObject
{
   protected const int VOLATILE_ID = -1;
   private int m_ID;
   protected DBObject(int ID) { m_ID = ID; }
   internal void SetID(int ID) { m_ID = ID; }
   public int ID { get { return m_ID; } }
}

class DBAccess
{
   void PersistObject(DBObject o)
   {
      if (o.GetID() == DBObject.VOLATILE_ID)
      {
        // insert object adhv o.GetType()
        o.SetID(NewID);
      }
      else
      {
         // update object adhv o.GetType() en o.GetID()
      }
   }
}

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • dtech
  • Registratie: Juni 2005
  • Laatst online: 13-06 23:19
Het enige verschil tussen jouw en mijn oplossing is dat jij een aparte class gebruikt om het model persistence te geven, terwijl dat bij mij door de model objects zelf gebeurd (dmv een static Create en een instance Store en Delete). Beide zijn valide implementaties van MVC, maar ik vind "mijn" manier mooier.

De DBAccess class kan eigenlijk ook wel static zijn, en als je consequent één type object naar een static class doorspeelt enkel en alleen om er iets mee te doen dan kan dat imho ook prima onderdeel van de classen zelf zijn.

Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

dtech schreef op zondag 16 mei 2010 @ 11:31:
Het enige verschil tussen jouw en mijn oplossing is dat jij een aparte class gebruikt om het model persistence te geven, terwijl dat bij mij door de model objects zelf gebeurd (dmv een static Create en een instance Store en Delete). Beide zijn valide implementaties van MVC, maar ik vind "mijn" manier mooier.

De DBAccess class kan eigenlijk ook wel static zijn, en als je consequent één type object naar een static class doorspeelt enkel en alleen om er iets mee te doen dan kan dat imho ook prima onderdeel van de classen zelf zijn.
Het punt is dat je nu voor elk database object een Store, Delete en Create moet schrijven, die bovendien in veel gevallen gelijk(-aardig) zijn. Daarenboven zit je database implementatie verweven in elk business object. Als je later van database wisselt moet je alle klasses overlopen en mogelijk aanpassen. Als je je datamodel wijzigt (zowel in C# als in je DB) moet je ook alles overlopen om zeker te zijn dat er niets breekt.
Zo'n tight coupling is gewoon een maintenance nightmare die je in het eerstvolgende donkere steegje staat op te wachten.

Bovendien denk ik dat je mijn approach niet echt begrijpt; Het is de bedoeling dat al je persisteerbare classes overerven van DBObject en je met een minimum aan aanpassingen in DBAccess je die objecten van die klasse kunt in je database opslaan. DBAccess is dus een generieke DB access layer, geen per-klasse access layer.

[ Voor 11% gewijzigd door H!GHGuY op 16-05-2010 12:38 ]

ASSUME makes an ASS out of U and ME

Pagina: 1