Überschreiben einer vererbten Property mit nachträglich bekanntem Typ

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von Rootbob91.

    Überschreiben einer vererbten Property mit nachträglich bekanntem Typ

    Hallo zusammen,

    aktuell möchte ich mir eine Basisklasse mit einer ganzzahligen numerischen Property bauen.
    Welchen Datentyp die Eigenschaft in abgeleiteten Klassen bekommt wird erst dort klar.

    C#-Quellcode

    1. public abstract class Foo
    2. {
    3. public abstract byte ID { get; set; }
    4. }
    5. public class DerivedFoo : Foo
    6. {
    7. public override short ID { get; set; }
    8. }
    9. public class DerivedFooTwo : Foo
    10. {
    11. public override int ID { get; set; }
    12. }


    VS meckert hier leider rum, dass die Datentypen in den abgeleiteten Klassen "byte" sein müssen. Ich benötige Dies allerdings nach Möglichkeit so wie oben geschildert.
    Ein Interface wollte ich vermeiden, damit ich dies nicht in jeder Klasse (mit anderen Funktionen) neu definieren muss.
    Polling is trolling!

    Achtung: Ich habe die komische Angewohnheit, simple Dinge zu verkomplizieren..
    Das funktioniert so leider nicht. Ein Beispiel, warum das nicht funktionieren kann:

    C#-Quellcode

    1. public class DerivedFooThree : Foo
    2. {
    3. public override byte ID { get; set; }
    4. }
    5. void DoSomethingWithFooId(Foo f)
    6. {
    7. byte id = f.ID;
    8. System.IO.File.WriteAllBytes("Test.bin", new byte[] {id});
    9. }
    10. void Test()
    11. {
    12. DoSomethingWithFooId(new DerivedFooThree() { ID = 0xFF }); // Würde einwandfrei funktionieren.
    13. DoSomethingWithFooId(new DerivedFooTwo() { ID = 0xFFFF }); // Was soll hier...
    14. DoSomethingWithFooId(new DerivedFoo() { ID = 0xFFFFFFFF }); // ...und hier passieren?
    15. }


    DoSomethingWithFooId kann ein Foo entgegennehmen. Das Liskov'sche Substitutionsprinzip verlangt, dass DoSomethingWithFooId deshalb auch alle abgeleiteten Klassen von Foo entgegennehmen können muss. Aber DerivedFooTwo und DerivedFoo können von DoSomethingWithFooId nicht verarbeitet werden, da die ID-Properties nun einen "zu großen Typ" haben würden. Es wäre nicht klar, was mit den Bits passiert, die nicht in das Byte passen, das DoSomethingWithFooId verarbeitet.


    Wenn Du uns mehr Informationen gibst, was Du eigentlich erreichen möchtest, dann können wir Dir eventuell Alternativen vorschlagen.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Hi
    mir würden da auf die Schnelle mehrere Möglichkeiten einfallen:
    • Interface IIDProvider<T>: Das Interface stellt den Typ bereit, für den eine ID verfügbar ist (sinnvoll, wenn man nach ID-Typ unterscheidet)
    • Integer als gemeinsamen Typen verlangen: Byte passt auch in Integer, somit wäre das die Vereinigungsmenge aller Werte, die möglich sind. Andererseits ist es nicht möglich, das so zu machen, wenn der Integer nur 0 bis 255 annehmen darf oder auch IDs vorhanden sein dürfen, die nicht in Integer (bzw. Long) passen.
    • Eine (ggf. serialisierbare) abstrakte Klasse ID, die IEquatable<ID> abstrakt implementiert, GetHashCode abstrakt überschreibt und Equals an IEquatable<ID>.Equals weiterreicht. Du würdest dann für die verschiedenen ID-Typen einen gemeinsamen nicht-generischen Basistypen zur Verfügung stellen.
    • Ein Object verwenden - das kann alle Typen halten, ist aber meines Erachtens unelegant und zwar aus mehreren Gründen: Du kannst den Typen des Objekts nur aus der Instanz selbst ableiten und musst daher häufig casten, was zu Object selbst relativ teuer ist (Boxing: Werte, wie Byte oder Int32 werden als Instanz im Heap erzeugt, wo sie quasi als Referenz zugreifbar sind). Außerdem ist das Operieren auf Object idR. recht mühseelig.
    • Ein Byte-Array (oder Long-Array). Würde ich nicht machen. Man ist nicht an bestimmte Regeln gebunden, was Aussehen und Struktur angeht. Außerdem gibt es bessere Typen.
    • Die verschiedenen IDs indirekt verwalten. Z.B. für jede ID eine eindeutige GUID finden.


    Meine Wahl wäre das Interface oder die abstrakte Klasse ID, wenn Integer als gemeinsamer Typ nicht möglich ist.

    Was außerdem noch möglich wäre, wäre, new (C#) bzw. Shadows (VB.Net), wenn du weißt, dass ein Typ nur Byte ist. Dann würdest du Shadows/new verwenden, um eine Eigenschaft mit identischem Namen anzugeben, die den Wert der Basis zu Byte konvertiert.

    Viele Grüße
    ~blaze~

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()

    Vielen Dank für eure Antworten und eure Zeit.
    Nach Umsetzung durch Interface und einer abstrakten Klassen, bin ich bei der abstrakten Klasse geblieben.
    Polling is trolling!

    Achtung: Ich habe die komische Angewohnheit, simple Dinge zu verkomplizieren..

    Rootbob91 schrieb:

    ...bin ich bei der abstrakten Klasse geblieben.

    Jeder benötigte Zahlentyp hat nun seine eigene abstrakte Basisklasse von der geerbt werden kann.
    Diese Klasse vererbt die jeweilige ID und die dazugehörige Funktionalität.
    Polling is trolling!

    Achtung: Ich habe die komische Angewohnheit, simple Dinge zu verkomplizieren..