我有以下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
,以便它们相当于复制上面的代码,为{{1}添加一些额外的字段使用“Extra”为所有类添加前缀,如下所示:
Node
实现这一目标的最佳方法是什么?我考虑过接口(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<T>, Element<T>, Document<T>
等等),但它仍会导致问题{{1因为ExtraNode : Node<MyExtraClass>
。
那么实现这一目标的最佳方法是什么,无需复制/粘贴整个文档并手动更改?我需要不止一次这样做。
修改以澄清我需要做什么,我需要以下代码才能运作:
(ExtraElement is ExtraNode) == false
编辑2: Kirk关于实现接口的建议(以Timwi的代码为例)在我的案例中是不切实际的,因为每个类都有很多字段和方法(总共大约有8个类),所以我必须为每个'Extra'派生组复制它们中的每一个。例如,这是Node类的外观:
(Element<MyExtraClass> is Node<MyExtraClass>) == false
因此每次都会复制30种方法。这适用于所有其他类。通过这种方法,我会复制这么多,我实际上复制了所有的代码。简单地复制/粘贴整个类,重命名并向其添加额外的字段会更容易。
答案 0 :(得分:1)
我认为Kirk Woll在评论中的想法几乎是最好的选择。我在代码中遇到了类似的问题,我提出了同样的想法。你真正希望能做的是拥有一个具有多重继承的继承树,而在C#中只有接口允许你这样做。
public interface INode { public INode Parent { get; } }
public interface IElement : INode { public Dictionary<string, string> Attributes { get; } }
public interface IDocument : IElement { ... }
public interface IExtraNode : INode { public int Priority { get; } }
public interface IExtraElement : IExtraNode, IElement { }
public interface IExtraDocument : IExtraElement, IDocument { ... }
现在你想要的所有属性都是真的:
element is INode // check
document is IElement // check
extraNode is INode // check
extraElement is INode // check
extraElement is IExtraNode // check
extraDocument is IExtraElement // check
extraDocument is IElement // check
extraDocument is INode // check
回应您的编辑#2:是的,您必须复制某些的实施,但不是很多。特别是,您不需要复制ExtraNode
中的任何内容(您可以继承Node
)。如果“额外”的内容不多,您只能复制额外的内容,即从ExtraElement
(而不是Element
)等继承ExtraNode
。
关于你在这里提到的问题:
public INode Parent { get; } // THIS IS WRONG, THIS SHOULD BE ExtraNode NOT INode
我认为这应该是IExtraNode
。您可以通过使用显式实现的属性来解决此问题(我现在假设您不从ExtraNode
派生Node
,但仅用于说明解决方案):
// Real code goes here
public IExtraNode Parent { get { return ...; } }
// This calls the property above, and implements the interface property
public INode INode.Parent { get { return Parent; } }
另一个编辑:您还可以声明一个名为Extra
的类,其中包含所有额外功能,并且ExtraNode
,ExtraElement
和{{1}所有都有ExtraDocument
类型的字段。您可以将此字段设为公共字段,也可以为其所有功能编写单行重定向方法。鉴于缺乏多重继承,这确实是最小的重复。
答案 1 :(得分:0)
您可以尝试使用mixin-like构造来共享必要的代码:
interface MNode {
MNode Parent { get; }
}
static class MNodeCode {
public static void Method1(this MNode self) { /*...*/ }
public static void Method2(this MNode self) { /*...*/ }
/* ... */
public static void Method30(this MNode self) { /*...*/ }
}
class Node : MNode {
public Node Parent { get { ... } }
MNode MNode.Parent { get { return Parent; } }
}
class Element : Node { public Dictionary<string, string> Attributes; }
class Document : Element { }
class ExtraNode : MNode {
public ExtraNode Parent { get { ... } }
MNode MNode.Parent { get { return Parent; } }
}
class ExtraElement : ExtraNode { public Dictionary<string, string> Attributes; }
class ExtraDocument : ExtraElement { }
您可以创建不同的mixin以获得不同的共享粒度。