c# - 派生类上的派生属性/字段:容器类及其字段之一上的“继承阶梯”
问题描述
如果已经回答,我想提前道歉。由于我不知道如何在标题中正确表达它,我可能错过了另一个类似的问题。我看到了这个,它很相似,但我认为它不完全相同,因为它的目标不是像我将描述的那样的层次结构。
假设我有一个基类和基字段,以及一个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
}
}
解决方案
您可以执行以下操作。给定您的基本类型;
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";
}
}
推荐阅读
- python - 使用带指数的输入/变量
- python - 使用 sqlalchemy 将数据插入 SQL Server db 会出现错误:“连接”对象没有属性“光标”
- python - Python - 在带有通配符的帖子中找到正确的链接
- c - 如何使用MinGW创建具有固定大小的内存段,将数据放置在段内的固定位置
- python - 在 python 中使用 selenium 根据来自 Ambari (HDFS) 的文件名下载文件
- python - UnboundLocalError:在赋值和数组之前引用了局部变量“actionNumber”
- javascript - 标准复选框和图像问题
- docker - 使用 Docker 映像时,如何在 Azure Devops 中处理多个发布阶段的应用设置?
- javascript - 在未定义中绑定时 Knex 抛出错误
- excel - 使用 Excel VBA 查找精确的多列匹配,然后组合/合并行