首页 > 解决方案 > 派生类上的派生属性/字段:容器类及其字段之一上的“继承阶梯”

问题描述

如果已经回答,我想提前道歉。由于我不知道如何在标题中正确表达它,我可能错过了另一个类似的问题。我看到了这个,它很相似,但我认为它不完全相同,因为它的目标不是像我将描述的那样的层次结构。

假设我有一个基类和基字段,以及一个DoStuff()作用于所述字段的方法

class MyContainer
{
    MyField field = new MyField();
    
    protected virtual void DoStuff()
    {
        field.foo1 = "a";
        field.foo2 = "b";
    }
}

现在,我想扩展 MyContainer,并创建 MyContainerExt,它还应该包含 MyField (MyFieldExt) 的派生版本。MyContainerExt 将覆盖 DoStuff() 以在 MyFieldExt 上做一些额外的事情,但我也希望我的基类中的 DoStuff() 完成:本质上,我想从基础 MyContainer 类中执行“基础”内容和初始化,并且添加可能需要在派生的 MyFieldExt 上添加的新字段/属性的额外初始化。

除此之外,假设现在我想要 MyContainerExtExt,它有一个从 MyFieldExt 派生的字段(即 MyFieldExtExt),我想在父类已经在做的事情之上做一些事情。

老实说,我不知道如何以有组织且无异味的方式解决这个问题。为了给您一个想法,这将是我想要的(如果您可以使用派生类型覆盖属性,我知道您不能这样做):

class MyContainer
{
    abstract MyField Foo {get; set; }
    
    protected virtual void DoStuff()
    {
        Foo.foo1 = "a";
        Foo.foo2 = "b";
    }
}


class MyContainerExt: MyContainer
{
    override MyFieldExt Foo {get; set;}  // I know, this is not legal

    protected override void DoStuff()
    {
        base.DoStuff();  // The DoStuff() from the base class is applied
        Foo.foo3 = "c";  // Potentially, foo3 and foo4 are fields added to MyFieldExt that
        Foo.foo4 = "d";  //    the base class MyField knows nothing about
    }
}


class MyContainerExtExt: MyContainerExt
{
    override MyFieldExtExt Foo {get; set;}  // I know, this is not legal (again)

    protected override void DoStuff()
    {
        base.DoStuff();  // The DoStuff() from the first derived class (MyContainerExt( is applied
        Foo.foo5 = "e";  // Again, foo5 and foo6 are fields added to MyFieldExtExt that
        Foo.foo6 = "f";  //    the base class MyFieldExt knows nothing about
    }
}

起初这可能没有意义,但我希望有一个层次结构,也许我在每个“继承级别”上有多个变体:

> MyContainer
>> MyContainerExt1, MyContainerExt2...
>>> MyContainerExt1Ext1, MyContainerExt1Ext2, MyContainerExt2Ext1, MyContainerExt2Ext2...

我想考虑这些类必须在它们的一个字段上做的共同因素:MyContainer 需要在其 MyField 类型字段上做的大部分(如果不是所有事情)都需要由它的所有孩子完成,与需要注意的是 MyContainer 的子代也具有 MyField 的派生版本。我还希望它相对容易扩展:我不希望有一个解决方案可以“管理”使这个阶梯最多可用于示例中的 3 级继承。我可能不需要更多,但我希望我正在制作的代码将来可以扩展,以防 MyContainerExtExtExt...Ext 或任何情况。

我根本不固定结构:它可以是基于属性的,也可以是子类必须重新实现的私有字段,或者其他什么。我只想要一种相对干净的方法来实现 MyField 的派生版本的初始化/工作,而无需将父 DoStuff() 中的所有行复制到子 DoStuff() 方法中(这会破坏继承点)。

如果有人想知道,我需要这个来在高度分层的 WPF 应用程序(ViewModel == MyContainer,Model == MyField)中构建我的模型和视图模型,但这不应该影响我认为的问题。

顺便说一句,我正在使用 .NET 4.5.2,所以在此之前欢迎任何新技巧。

编辑: 我最终得到了与下面 InBetween 的答案非常相似的东西。这是我在问之前想要做的,但它似乎并不正确,所以我想仔细检查没有标准/更好的方法。我的最终结构类似于:

class MyContainer
{
    protected MyField Foo {get; set; }

    public MyContainer()
    {
        Foo = new MyField();
    }
    
    protected virtual void DoStuff()
    {
        Foo.foo1 = "a";
        Foo.foo2 = "b";
    }
}


class MyContainerExt: MyContainer
{
    public MyContainerExt()
    {
        Foo = new FieldExt();  // no need to override anything for this to work
    }

    protected override void DoStuff()
    {
        base.DoStuff();  // The DoStuff() from the base class is applied
        
        MyFieldExt foo = (MyFieldExt)Foo;  // The cast always works, since Foo is initialized as FieldExt
        foo.foo3 = "c";  // Potentially, foo3 and foo4 are fields added to MyFieldExt that
        foo.foo4 = "d";  //    the base class MyField knows nothing about
    }
}


class MyContainerExtExt: MyContainerExt
{
    public MyContainerExtExt()
    {
        Foo = new FieldExtExt();  // no need to override anything for this to work
    }

    protected override void DoStuff()
    {
        base.DoStuff();  

        MyFieldExtExt foo = (MyFieldExtExt)Foo;  // The cast always works, since Foo is initialized as FieldExtExt
        Foo.foo5 = "e";  // Again, foo5 and foo6 are fields added to MyFieldExtExt that
        Foo.foo6 = "f";  //    the base class MyFieldExt knows nothing about
    }
}

标签: c#inheritance

解决方案


您可以执行以下操作。给定您的基本类型;

class MyContainer
{
    abstract MyField Foo {get; set; }

    protected virtual void DoStuff()
    {
        Foo.foo1 = "a";
        Foo.foo2 = "b";
    }
}

无需MyField在派生类型中重新声明,只需将其转换为更具体的类型:

class MyContainerExt: MyContainer
{

    protected override void DoStuff()
    {
        base.DoStuff();
        var specificFoo = Foo as MyFieldExt; //this cast will always succeed
        specificFoo.foo3 = "c";  
        specificFoo.foo4 = "d";
    }
}

推荐阅读