typedef-Alternative in C#



  • Folgenden Code (aufs Wesentliche reduziert) wollte ich verbessern, um auch von Gizmo abgeleitete Objekte zu unterstützen:

    public class GizmoList : List<Gizmo>
    {
        public GizmoList FilterBy(string cond) { ... }
        public void Merge(GizmoList rhs) { ... }
    }
    

    Erster Versuch: ein Typargument mit Constraint. Nur gibt es leider sehr viel Code, der schon die GizmoList verwendet und den ich nicht anpassen will. Also:

    using GizmoList = GizmoList<Gizmo>;
    public class GizmoList<GizmoT> : List<Gizmo>
        where GizmoT : Gizmo
    {
        public GizmoList<GizmoT>FilterBy(string cond) { ... }
        public void Merge(GizmoList<GizmoT> rhs) { ... }
    }
    

    Leider führt das aber nicht zum gewünschten Ergebnis, weil das using-Statement nur im aktuellen Unit gilt. In C++ hätte ich einfach ein typedef verwendet und alles wäre gut; nur leider gibts das in C# nicht.

    Also habe ich die nächstbeste Alternative ausprobiert und eine Klasse abgeleitet:

    public class GizmoList : GizmoList<Gizmo> {}
    

    Das ist schon besser. Dennoch geht viel Code kaputt, und zwar immer, wenn er sowas macht:

    GizmoList filteredList = gizmoList.FilterBy("...");
    

    Also habe ich die Zähne zusammengebissen und das hier konstruiert:

    public class GizmoListBase<DerivedT, GizmoT> : List<GizmoT>
        where DerivedT : GizmoListBase<DerivedT, GizmoT>, new()
        where GizmoT : Gizmo
    {
        public DerivedT FilterBy(string cond) { ... }
        public void Merge(DerivedT rhs) { ... }
    }
    
    // compatibility
    public class GizmoList : GizmoListBase<GizmoList, Gizmo> {}
    
    // would everyone PLEASE use this one instead of your homegrown subclass?
    public class GizmoList<Gizmo> : GizmoListBase<GizmoList<Gizmo>, Gizmo>
        where GizmoT : Gizmo
    {
    }
    

    Das kanns aber doch nicht sein. Vielleicht bin ich zu sehr an C++ gewöhnt, aber mir fehlen da Typedefs. Und irgendwie sehe ich schon ein, daß man für GizmoList<VeryCommonGizmo> gerne einen kürzeren Namen hat; also will ich die Leute, die abgeleitete Klassen als Typedef-Ersatz eingeführt haben, auch nicht rundheraus verurteilen.

    Wie würde man das Problem idiomatisch lösen? Muß ich damit leben, mir so eine aufgeblasene GizmoListBase<> zu definieren? Oder gibt es bessere Alternativen?



  • Hallo Audacia (On ;-),

    ist mir beim Umstieg von C++ auf C# auch ersteinmal so gegangen, daß ich typedefs vermisst habe. Und in meinen ersten Versuchen habe ich dann auch immer eigene von List<X> oder Dictionary<X, Y> abgeleitete Klassen erstellt (<= .NET 2.0).
    Als Nachteil habe ich dann festgestellt, daß man dann ja auch immer die Konstruktoren neuimplementieren muß (insb. den "Kopierkonstruktor").
    Seit .NET 3.0 jedoch verwende ich fast nur noch Interfaces und Extension Methods.

    Besteht deine Klasse GismoList denn nur aus den 2 beschriebenen Methoden, oder hat diese noch mehr (private) Member?
    Falls es nur "Convenience Methods" sind, dann würde ich vorschlagen, diese neu als Extension Methods zu implementieren.
    Für den Aufrufer gibt es dann natürlich keine eigene Klasse GizmoList mehr, sondern dann nur noch List<Gizmo> bzw. noch besser IList<Gizmo> oder IEnumerable<Gizmo>.



  • Th69 schrieb:

    oder hat diese noch mehr (private) Member?

    Leider ja.

    Th69 schrieb:

    Für den Aufrufer gibt es dann natürlich keine eigene Klasse GizmoList mehr, sondern dann nur noch List<Gizmo> bzw. noch besser IList<Gizmo> oder IEnumerable<Gizmo>.

    Damit hätte ich wieder dasselbe Problem wie am Anfang. Ich stimme zu, daß Extension Methods mit Constraint die bessere Lösung sind. Aber halt nur, wenn man früh genug dran denkt.


Log in to reply