6 Stimmen

Generischer Elternteil für generische Klasse

Ich verwende dazu ein fiktives Beispiel. Sagen wir, ich habe eine Widget-Klasse wie:

abstract class Widget
{
Widget parent;
}

Nun würden meine anderen Klassen von dieser Widget-Klasse abgeleitet werden, aber nehmen wir an, ich möchte eine Einschränkung in die Klasse aufnehmen, während ich die abgeleiteten Typen definiere, so dass nur ein bestimmter "Typ" von Widget einem bestimmten Typ von Widget übergeordnet sein kann.

Ich habe zum Beispiel zwei weitere Widgets von der Widget-Klasse abgeleitet, WidgetParent und WidgetChild. Bei der Definition der Child-Klasse möchte ich den Typ des Elternteils als WidgetParent definieren, damit ich nicht jedes Mal, wenn ich es verwende, den Typ des Elternteils ändern muss.

Genau, das hätte ich gerne getan:

// This does not works!
class Widget<PType>: where PType: Widget
{
    PType parent;
}

class WidgetParent<Widget>
{
    public void Slap();
}

class WidgetChild<WidgetParent>
{
}

Wenn ich also auf das übergeordnete Element von WidgetChild zugreifen möchte, anstatt es auf diese Weise zu verwenden:

WidgetParent wp = wc.parent as WidgetParent;
if(wp != null)
{
    wp.Slap();
}
else throw FakeParentException();

Ich möchte es auf diese Weise verwenden (wenn ich Generika verwenden könnte):

wc.parent.Slap();

9voto

Jon Skeet Punkte 1325502

Sie sollten in der Lage sein, den Code, den Sie haben, zu verwenden, indem Sie weiterhin die nicht-generische Klasse Widget und die Herstellung Widget<T> daraus ableiten:

public abstract class Widget
{
}

public abstract class Widget<T> : Widget where T : Widget
{
}

Sie müssen dann herausfinden, was in die generische Klasse gehört und was in die nicht-generische... erfahrungsgemäß kann dies ein schwieriger Balanceakt sein. Rechnen Sie damit, dass Sie ziemlich viel hin- und hergehen müssen!

1voto

Lasse V. Karlsen Punkte 364542

Schnittstellen verwenden:

interface IContainerWidget { }

class Widget
{
    private IContainerWidget Container;
}

class ContainerWidget : Widget, IContainerWidget
{
}

0voto

chakrit Punkte 59834

Ich glaube nicht, dass es einen sprachlichen Mechanismus gibt, der dies zulässt.

Möglicherweise möchten Sie jedoch eine Fabrikmuster die Konstruktion der Klasse von der Klasse selbst zu trennen .

Nehmen wir an, Sie erstellen eine WidgetFactory-Klasse

class WidgetFactory
{
    Widget CreateWidget()
    {
        return new Widget();
    }
}

Und für Kinderklassen würden Sie auch deren Fabrik bauen. Sagen wir, eine WidgetParentFactory oder WidgetChildFactory oder Sie könnten eine generische Fabrik machen:

class WidgetFactory<T> where T : Widget
{
    T CreateWidget()
    {
        return new T();
    }
}

Dann könnten Sie mit der CreateWidget()-Methode die Instanziierung der Klasse so steuern, dass keine ungültigen Kindtypen erstellt werden können.

class WidgetFactory<T> where T : Widget
{
    T CreateWidget()
    {
        if (/*check the type T inheritance here*/)
            return new T();
        else
            throw new Exception("Invalid inheritance");
    }
}

Das sollte für Sie ausreichen.

p.s. Würden Sie bitte Folgendes näher erläutern warum Sie wollten das tun?

0voto

James Curran Punkte 98228

Sie scheinen Typparameter und Vererbung zu verwechseln. Dies sollte funktionieren:

class Widget<PType> where PType :new()
{
    public  PType parent = new PType();
}

class ParentType {}

class WidgetParent : Widget<ParentType> 
{    
    public void Slap() {Console.WriteLine("Slap"); }
}

class WidgetChild : Widget<WidgetParent>
{
}
public static void RunSnippet()
{
    WidgetChild wc = new WidgetChild();
    wc.parent.Slap();
}

0voto

Amy B Punkte 104656

Hier ist mein Versuch, dies zu organisieren.

public interface IWidget
{
    void Behave();
    IWidget Parent { get; }
}

public class AWidget : IWidget
{
    IWidget IWidget.Parent { get { return this.Parent; } }
    void IWidget.Behave() { this.Slap(); }

    public BWidget Parent { get; set; }
    public void Slap() { Console.WriteLine("AWidget is slapped!"); }
}

public class BWidget : IWidget
{
    IWidget IWidget.Parent { get { return this.Parent; } }
    void IWidget.Behave() { this.Pay(); }

    public AWidget Parent { get; set; }
    public void Pay() { Console.WriteLine("BWidget is paid!"); }
}

public class WidgetTester
{
    public void AWidgetTestThroughIWidget()
    {
        IWidget myWidget = new AWidget() { Parent = new BWidget() };
        myWidget.Behave();
        myWidget.Parent.Behave();
    }
    public void AWidgetTest()
    {
        AWidget myWidget = new AWidget() { Parent = new BWidget() };
        myWidget.Slap();
        myWidget.Parent.Pay();
    }

    public void BWidgetTestThroughIWidget()
    {
        IWidget myOtherWidget = new BWidget() { Parent = new AWidget() };
        myOtherWidget.Behave();
        myOtherWidget.Parent.Behave();
    }

    public void BWidgetTest()
    {
        BWidget myOtherWidget = new BWidget() { Parent = new AWidget() };
        myOtherWidget.Pay();
        myOtherWidget.Parent.Slap();
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X