通用的父类用于通用类

8

我将使用一个虚构的例子来说明。比如,我有一个像这样的 Widget 类:

abstract class Widget
{
Widget parent;
}

现在,我的其他类将从这个Widget类派生出来,但是假设我想在定义派生类型时对该类施加一些约束,以便只有特定“类型”的widget可以成为特定类型的Widget的父级。
例如,我已经从Widget类派生了两个小部件,WidgetParent和WidgetChild。在定义子类时,我希望将父类的类型定义为WidgetParent,这样我每次使用它时都不必强制转换父类。
确切地说,我想做的就是这样:
// This does not works!
class Widget<PType>: where PType: Widget
{
    PType parent;
}

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

class WidgetChild<WidgetParent>
{
}

当我想要访问WidgetChild的父级时,不要使用以下方式:

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

我希望能这样使用它(如果我可以使用泛型):
wc.parent.Slap();
6个回答

11

您应该能够通过仍然拥有非泛型类Widget并使Widget<T>从中派生来使用您已经获得的代码:

public abstract class Widget
{
}

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

然后你需要确定哪些内容属于通用类,哪些内容属于非通用类... 根据经验,这可能是一个棘手的平衡行为。预计需要来回多次调整!


1

使用接口:

interface IContainerWidget { }

class Widget
{
    private IContainerWidget Container;
}

class ContainerWidget : Widget, IContainerWidget
{
}

0

我认为没有一种语言机制可以让你这样做。

但是,你可能想使用工厂模式来将类的构建与类本身分离

比如,创建一个WidgetFactory类。

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

对于子类,您也需要创建它们的工厂。比如,WidgetParentFactory或WidgetChildFactory,或者您可以创建一个通用的工厂:

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

然后从CreateWidget()方法中,您可以控制类的实例化,以便无法创建无效的子类型。

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

这应该能为您解决问题。

p.s. 您是否愿意详细说明一下为什么想要这样做呢?


感谢你的努力,chakrit。我已经详细说明了用法。 - nullDev

0

您似乎把类的类型参数和继承混淆了。以下代码应该可以解决这个问题:

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();
}

我原以为这个点是要限制父类型也必须是某种小部件。 - Jon Skeet
@Jon: 没错,父级有所述的约束条件。 - nullDev

0

这是我尝试组织它的方式。

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();
    }
}

0

我曾经遇到过类似的问题,并进行了相应的调整(希望能够解决)

主要代码

public class Parent<T>
    where T : Child<T>
{
    public Parent() { }


    public T Get()
    {
        return Activator.CreateInstance(typeof(T), new object[] { this }) as T;
    }
}

public class Child<T>
    where T : Child<T>
{
    Parent<T> _parent;

    public Parent<T> Parent { get { return _parent; } }

    public Child(Parent<T> parent)
    {
        _parent = parent;
    }
}


public class ItemCollection : Parent<Item>
{

}

public class Item : Child<Item>
{
    public Item(Parent<Item> parent)
        : base(parent)
    {
    }
}

例子:

ItemCollection col = new ItemCollection();
Item item = col.Get();
item.Parent.Slap();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接