| 

.NET C# Java Javascript Exception

2
Hey,
ich habe folgende C#-Object-Struktur (inkl. weiterer Methoden die aber für die Frage unrelevant sind):
abstract class Element
{
public const string NODENAME = "element";
protected Element Parent{get; set;}
public Element(Element parent)
{
this.Parent = parent;
}

public string CalculatePath(string path = "")
{
string currentPath = NODENAME + "." + path;
return Parent != null ? Parent.CalculatePath(currentPath) : currentPath;
}
}

class Topic : Element
{
public new const string NODENAME = "topic";
public Topic(Element parent) : base(parent) {}
}


Wenn ich nun auf dieser Struktur auf einem Topic-Objekt die Methode "CalculatePath()" aufrufe erhalte ich immer nur Ausgaben wie "element.element." oder "element.". Statt dessen möchte ich eine Ausgabe wie "topic.topic.element.". Im Prinzip sollte die vererbte Methode den NODENAME des konkreten Objektes verwenden und nicht der Abstrakten Klasse. Hat jemand einen Tipp wie ich genau dies umgehen kann?

Vielen Dank!
17.08.2011
najjannaj 63 3
3 Antworten
4
So müsste Deine abstrakte Klasse ja etwas von der konkreten Implementierung kennen (nämlich die Konstante NODENAME) - das soll (und darf) nicht sein.
"new" ist in dem Context eigentlich nur für den Compiler gedacht, der sonst nicht zwischen den beiden NODENAME-Feldern unterscheiden könnte. Topic.NODENAME bleibt aber dennoch nur über die Topic-Klasse verfügbar und die abstrakte Klasse kennt trotzdem nur seine eigene Definition.
Oder noch einfacher ausgedrückt: "Element" ist es vollkommen egal, ob "Topic" da ist oder nicht ;)

Stattdessen würde ich in etwa folgendes schreiben
abstract class Element {
public const string NODENAME = "element";

public virtual string CalculatePath( ) {
return NODENAME;
}
}

class Topic : Element {
public new const string NODENAME = "topic";

public override string CalculatePath( ) {
return string.Format( "{0}.{1}", base.CalculatePath( "" ), NODENAME );
}
}
Ob das nachher Sinnvoll ist, und vor allem, wie Du die einzelnen Texte zusammensetzt sei Dir überlassen. Ich hab den Teil mit dem Parent weggelassen, da hierfür nicht nötig.
Du musst nur noch sicherstellen, dass Du die Methode über die Topic-Instanz aufrufst. Das Spiel kannst Du so endlos betreiben (also z.B. mit einer weiteren Klasse die von Topic erbt) - sie muss nur CalculatePath überschreiben.


Was anderes: Default-Werte sind mächtig böse und im Alltag eher zu vermeiden ;) Für COM sicherlich noch daseinsberechtigt, ansonsten maximal für private-member sinnbehaftet. Grund ist, dass der Default-Wert als Konstante verwendet wird, d.h. zur Compile-Zeit festgelegt wird. Ändert sich Deine Konstante, müssten alle Assemblies, in denen diese Funktion aufgerufen wird, ebenfalls neu kompiliert werden - und wer denkt da schon dran (vor allem, wenn Du Deine Assembly weitergibst und andere darauf zugreifen können) ;)

Besser (wenn auch etwas umfangreicher)
public string CalculatePath(string path){
// ...
}
public string CalculatePath( ){
return CalculatePath("");
}



Edit: Auf Tachyons Anregung hin eine etwas einfachere Form
abstract class Element {
public virtual string NodeName {
get {
return "element";
}
}
}

class Topic : Element {
public override string NodeName {
get {
return base.NodeName + ".topic";
}
}
}
17.08.2011
WolfgangKluge 1,0k 2 7
Vielen Dank :)
Dachte ursprünglich ich könnte einen Weg finden die Methode nicht in jeder Klasse die von Element erbt unterbringen zu müssen. Aber es scheint wohl nur dieser Weg zu funktionieren. Danke!
najjannaj 17.08.2011
2
Hallo,

WolfgangKluge hat es ja weitesgehend schon erklärt.

Vielleicht noch als Ergänzung... ich nehme in diesen Fällen gerne eine virtuelle Property (Wenn es Sinn macht das ein Defaultwert existiert) oder falls Defaultwerte keinen Sinn ergeben eine abstrakte Property. Damit wird die abgeleitete Klasse gezwungen einen Wert für die Property zu definieren.

Die Property kann dann natürlich schon für Funktionalität in der Basisklasse verwendet werden.

<edit>
Achso, es ist natürlich wichtig, dass die Property (gilt natürlich auch für Methoden) virtuell ist und mit "overwrite" überschrieben wird. Mit "new" können Properties nicht überschrieben werden, es wird lediglich für den Typen eine neue Property definiert welche die alte quasi verdeckt. Wird eine Variable vom Typ des Basistypen verwendet, so wird auch die Property des Basistypen und nicht die mit "new" definierte Property verwendet.

Also vorsicht bei der Verwendung von "new" (ich habs ehrlich gesagt noch nie benötigt).
</edit>

Viele Grüße,
Tachyon
17.08.2011
Tachyon 690 1 7
Tachyon 690 1 7
0
stimmt nicht, bitte entfernen
17.08.2011
KN 1,7k 1 8
KN 1,7k 1 8

Stelle deine .net-Frage jetzt!
TOP TECHNOLOGIES CONSULTING GmbH