类派生问题
我有以下 3 个类:
class Node {
public Node Parent;
// Edit: to clarify, each of these classes has many fields and methods
public void Method1() { /*...*/ }
public void Method2() { /*...*/ }
/* ... */
public void Method30() { /*...*/ }
}
class Element : Node { public Dictionary<string, string> Attributes; }
class Document : Element { }
我需要一种方法来定义 ExtraNode
、ExtraElement
和 ExtraDocument
,以便它们相当于复制上面的代码,向 Node
类添加一些额外的字段,并为所有类添加“Extra”前缀,如下所示:
class ExtraNode { public Node Parent; public int Priority; }
class ExtraElement : ExtraNode { public Dictionary<string, string> Attributes; }
class ExtraDocument : ExtraElement { }
实现此目的的最佳方法是什么?我考虑过接口 (ExtraNode : Node, IExtra
),但后来 (ExtraElement is ExtraNode) == false
。
我还考虑过将类重写为泛型(Node
),然后使用它们来定义新类(ExtraNode : Node
等等),但仍然会导致 (ExtraElement is ExtraNode) == false
的问题,因为 (Element
。
那么,在不复制/粘贴整个文档并手动更改的情况下实现此目的的最佳方法是什么?我需要不止一次地这样做。
编辑:为了澄清我需要能够做什么,我需要以下代码才能工作:
// this should accept an ExtraNode, an ExtraElement or an ExtraDocument:
void doSomethingWithANode(ExtraNode extraNode) { ... }
编辑2:柯克关于实现接口的建议(如 Timwi 的代码所示)在我的例子中是不切实际的,因为每个类都有许多字段和方法(总共大约有 8 个类),所以我必须为每个“额外”派生组复制其中的每一个。例如,Node 类如下所示:
class INode {
INode Parent { get; }
void Method1();
void Method2();
/* ... */
void Method30();
}
class ExtraNode {
public int Priority { get; } // extra
public INode Parent { get; } // THIS IS WRONG, THIS SHOULD BE ExtraNode NOT INode
public void Method1() { ... } // here I have to define the entire method
public void Method2() { ... }
/* ... */
public void Method30() { ... }
}
class SuperNode {
public string Superpower { get; } // extra
public INode Parent { get; } // THIS IS WRONG, THIS SHOULD BE SuperNode NOT INode
public void Method1() { ... } // here I have to define the entire method AGAIN
public void Method2() { ... } // all methods are identical to the ones in ExtraNode
/* ... */
public void Method30() { ... } // this is unnecessary code duplication
}
因此每次都会重复 30 个方法。这适用于所有其他类别。通过这种方法,我会复制很多内容,几乎复制所有代码。只需复制/粘贴整个类、重命名并向其中添加额外的字段会更容易。
I have the following 3 classes:
class Node {
public Node Parent;
// Edit: to clarify, each of these classes has many fields and methods
public void Method1() { /*...*/ }
public void Method2() { /*...*/ }
/* ... */
public void Method30() { /*...*/ }
}
class Element : Node { public Dictionary<string, string> Attributes; }
class Document : Element { }
I need to have a way to define ExtraNode
, ExtraElement
and ExtraDocument
so that they are the equivalent of copying the code above, adding a few extra fields to the Node
class, and prefixing all classes with "Extra", like so:
class ExtraNode { public Node Parent; public int Priority; }
class ExtraElement : ExtraNode { public Dictionary<string, string> Attributes; }
class ExtraDocument : ExtraElement { }
What is the best to achieve this? I thought about interfaces (ExtraNode : Node, IExtra
), but then (ExtraElement is ExtraNode) == false
.
I also thought about rewriting the classes as generics (Node<T>, Element<T>, Document<T>
), then using them to define the new classes (ExtraNode : Node<MyExtraClass>
and so on), but it still leads to the problem of (ExtraElement is ExtraNode) == false
because (Element<MyExtraClass> is Node<MyExtraClass>) == false
.
So what is the best way of achieving this, without copy / pasting the entire document and changing by hand? I will need to do this more than once.
Edit: to clarify what I need to be able to do, I need the following code to work:
// this should accept an ExtraNode, an ExtraElement or an ExtraDocument:
void doSomethingWithANode(ExtraNode extraNode) { ... }
Edit 2: Kirk's suggestion about implementing interfaces (as exemplified by Timwi's code) is impractical in my case because each class has many fields and methods (and there are about 8 classes in total), so I would have to copy each and every one of them for each 'Extra' derivate group. For example this is how the Node classes would look:
class INode {
INode Parent { get; }
void Method1();
void Method2();
/* ... */
void Method30();
}
class ExtraNode {
public int Priority { get; } // extra
public INode Parent { get; } // THIS IS WRONG, THIS SHOULD BE ExtraNode NOT INode
public void Method1() { ... } // here I have to define the entire method
public void Method2() { ... }
/* ... */
public void Method30() { ... }
}
class SuperNode {
public string Superpower { get; } // extra
public INode Parent { get; } // THIS IS WRONG, THIS SHOULD BE SuperNode NOT INode
public void Method1() { ... } // here I have to define the entire method AGAIN
public void Method2() { ... } // all methods are identical to the ones in ExtraNode
/* ... */
public void Method30() { ... } // this is unnecessary code duplication
}
So 30 methods are duplicated every single time. And this applies for all the other classes. By this method I would duplicate so much, I'm practically duplicating all the code. It would be easier to simply copy / paste the entire class, rename and add the extra fields to them.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为柯克沃尔在评论中的想法几乎是最好的选择。我在代码中遇到了类似的问题,并且提出了相同的想法。您真正想要做的是拥有一个具有多重继承的继承树,而在 C# 中,只有接口允许您这样做。
现在您想要的所有属性都是 true:
响应您的编辑#2:是的,您必须复制一些实现,但不是很多。特别是,您不需要在
ExtraNode
中复制任何内容(您只需从Node
继承即可)。如果“额外”的东西不多,你可以只复制额外的东西,即从Element
继承ExtraElement
(而不是从ExtraNode
)等等。关于你在这里提到的问题:
我相信这应该是
IExtraNode
。您可以通过使用显式实现的属性来解决此问题(我现在假设您没有从Node
派生ExtraNode
,但仅来说明解决方案):又一个编辑:您还可以声明一个名为
Extra
的类,其中包含所有额外功能,并具有ExtraNode
,ExtraElement
和ExtraDocument
都有一个Extra
类型的字段。您可以公开该字段,也可以为其所有功能编写一行重定向方法。鉴于缺乏多重继承,这确实是最少的重复。I think Kirk Woll’s idea in the comments is pretty much the best option. I ran into a similar problem in my code, and I came up with the same idea. What you really want to be able to do is have an inheritance tree with multiple inheritance, and in C# only interfaces allow you this.
Now all the properties you wanted are true:
Responding to your Edit #2: Yes, you would have to duplicate some of the implementations, but not many. In particular, you don’t need to duplicate anything in
ExtraNode
(you can just inherit fromNode
). If the “extra” stuff is not much, you can duplicate only the extra stuff, i.e. inheritExtraElement
fromElement
(instead of fromExtraNode
) etc.Regarding the problem you mentioned here:
I believe this should be
IExtraNode
. You can solve this by using an explicitly-implemented property (I’m assuming now that you’re not derivingExtraNode
fromNode
, but only to illustrate the solution):Yet another edit: You could also declare a class called
Extra
which contains all the extra functionality, and haveExtraNode
,ExtraElement
andExtraDocument
all have a field of typeExtra
. You could either make this field public, or you could write one-line redirect methods for all its functionality. This is truly a minimum of duplication, given the lack of multiple inheritance.您可以尝试使用 mixin-like 构造共享必要的代码:
您可以创建不同的 mixin 以获得不同的共享粒度。
You could try to use a mixin-like construct to share the necessary code:
You can create different mixins to get a different sharing granularity.