C# - Property aus abstrakter Klasse erben

Dey

Banned
Registriert
Mai 2005
Beiträge
1.925
Hey.

Da C# für mich noch Neuland ist, bräuchte ich eure Unterstützung bei der Lösung des folgenden Problems:

Ich habe eine abstrakte Klasse, die neben einigen Members die Property

Code:
private List<string> _FormatterCollection = null;

        public List<string> FormatterCollection
        {
            get {
                return _FormatterCollection;
            }
        }

besitzt. Da ich eine Warnmeldung erhalte, wenn ich den privaten Member _FormatterCollection nur deklariere, weise ich der Variablen den Wert "null" zu.

In der Klasse "DateTimeTypeConverter" leite ich die abstrakte Klasse ab. Da FormatterCollection nun eine bestimmte Menge von String-Objekten enthalten soll, definiere ich folgenden Code im Konstruktor:

Code:
        public DateTimeTypeConverter()
        {
            this._FormatCollection =  new List<string> { "TT.MM.JJJJ", "JJJJ.MM.TT", "DD.MM.YYYY", "MM.DD.YYYY" };
        }

Nun zum eigentlichen Problem: Die List<string> erhält in der Klasse "DateTimeTypeConverter" zunächst einmal einige Werte. Danach wird jedoch die in der abstrakten Klasse definierte Zuweisung ausgeführt, wodurch FormatterCollection wieder auf null gesetzt wird.

Wenn ich also eine Instanz von "DateTimeTypeConverter" erstelle, ist seine Property FormatterCollection gleich null.

Wie kann ich dieses Problem umgehen?
 
z.B. eine abstrakte Methode

Code:
private List<string> _FormatterCollection = createFormatterCollection();

protected abstract List<string> createFormatterCollection();

Zudem weist du eh "_FormatCollection" anstelle von "_FormatterCollection" zu... kann ja wohl nicht gehen. Letzteres kann eh nicht verändert werden in der abgeleiteten Klasse, da privat...
 
Zuletzt bearbeitet:
Ich habe noch vergessen zu erwähnen, dass die abstrakte Klasse ein Interface implementiert, in welchem die Signaturen von Members definiert sind:

Code:
   public interface IFormatter
    {
         string Format(string format, System.Globalization.CultureInfo culture, object arg);

         List<string> FormatterCollection { get; }
    }

Die Lösung mit zusätzlichen Methoden ist eine reine Notlösung. Aber elegant ist diese Lösung aus meiner Sicht nicht.

Ich habe es mit "Protected"-Eigenschaften versucht, aber auch hierbei wird der Wert wieder auf null gesetzt:

Code:
 protected List<string> _FormatterCollection;

        public List<string> IFormatter.FormatterCollection
        {
            get { return _FormatterCollection; }
        }

Ist es nicht irgendwie möglich, dass zuerst der Code in der abstrakten Klasse ausgeführt wird und dann derjenige in den abgeleiteten? Sodass die Eigenschaft zwar zunächst auf null gesetzt wird, aber danach wie gewünscht Werte erhält?
 
Für Dein Problem gibt es verschiedene Lösungswege. Welcher der Beste ist, hängt natürlich ganz stark von Deinem Anwendungsfall ab.

Wie 1668mib schreibt, kannst Du die Initialisierung der Liste über eine abstrakte Methode, die Du in der abgeleiteten Klasse implementierst, vornehmen. Dieser Weg ist allerdings nicht unbedingt der beste, da er in der abgeleiteten Klasse eine Abhängigkeit erzeugt, die Du eventuell vermeiden kannst - schliesslich muss jeder, der von der abstrakten Klasse eine konkrete Implementierung erzeugt die Liste instanziieren (nicht mit Initialisieren verwechseln, dies kann sehr wohl in der konkreten Klasse sehr sinnvoll angebracht sein), ein Quell von Fehlern und Missverständnissen, den man vermeiden sollte.

Da die Property der Liste nur einen Getter und keinen Setter hat, wäre in Deinem Fall wahrscheinlich das direkte Instanziieren der Liste bei der Deklaration in der abstrakten Klasse am angebrachtesten.

Code:
private readonly List<string> _FormatterCollection = new List<string>();
     
public List<string> FormatterCollection
{
get { return _FormatterCollection; }
}

Alternativ kannst Du natürlich auch einen Setter mit der Sichtbarkeit protected in Deinen Code einbauen (dann ist auch das Initialisieren der Liste bei der Deklaration hinfällig). Du kannst in diesem Fall auch eine auto-implemented property verwenden, die private Deklaration des Feldes kann dann entfallen.

Code:
public List<string> FormatterCollection { get; protected set; }

Dieser Code ist allerdings nur dann sinnvoll, wenn die abgeleitete Klasse das Instanziieren der Liste zwingend selbst durchführen muss - siehe meinen oben angegebenen Kommentar.
 
@Dey: Hast du auch "this._FormatCollection" in "this._FormatterCollection" geändert?

@KaSpel: Natürlich, meine Variante hatte nicht den Anspruch, die perfekte zu sein... die Wahl der Lösung hängt wie angesprochen von vielen Faktoren ab, aber bei den hier bekannten Informationen kann man keine wirkliche Empfehlung machen.
 
KaSpel schrieb:
Code:
public List<string> FormatterCollection { get; protected set; }

Dieser Code ist allerdings nur dann sinnvoll, wenn die abgeleitete Klasse das Instanziieren der Liste zwingend selbst durchführen muss - siehe meinen oben angegebenen Kommentar.

So sollte es sein. Bzgl. des Hinweises, die abstrakte Klasse kann die Collection auch mit den Standard-Werten initialisieren.

Dennoch, wieso ich überhaupt noch antworte.
Das Fehlverhalten, wie du es beschreibst ist unmöglich. Die Ausführungsreihenfolge ist immer von oben nach unten, soll heißen das als erstes immer das ausgeführt wird, was in der Base-Class steht. Demnach kann es gar nicht sein, dass die Collection, wenn sie von einer abgeleiteten Klasse initialisiert wurde, von der Abstrakten wieder mit null überschrieben wird.
 
Hi.

Das Fehlerverhalten rührt tatsächlich daher, dass ich zwei unterschiedliche Properties ansprach (_FormatterCollection und _FormatCollection). Da ist mir ein sehr hässlicher Fehler unterlaufen bei der Programmierung.

Und ich habe ihn nicht entdeckt, weil ich davon ausging, dass ich bei C# irgendwelche Besonderheiten zu beachten habe. Natürlich muss zunächst der Code in der Basisklasse ausgeführt werden und erst danach der Code in den Subklassen.

Jetzt nach der Änderung funktioniert es auch. Ich danke allen Beteiligten vielmals für die Hilfe! Und natürlich auch für die weiteren Tipps.
 
Zurück
Oben