我有以下三门课:
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类中添加一些额外的字段,并在所有类的前缀中加上“额外”,如下所示:
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>),然后使用它们来定义新类(ExtraNode : Node<MyExtraClass>等等),但它仍然会导致(ExtraElement is ExtraNode) == false的问题,因为(Element<MyExtraClass> is Node<MyExtraClass>) == false。
那么,在不复制/粘贴整个文档并手动更改的情况下,实现这一目标的最佳方法是什么呢?我需要这样做不止一次。
编辑:为了澄清我需要做什么,我需要以下代码才能工作:
// this should accept an ExtraNode, an ExtraElement or an ExtraDocument:
void doSomethingWithANode(ExtraNode extraNode) { ... }编辑2: Kirk关于实现接口的建议(如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种方法。这也适用于其他所有的类。通过这种方法,我会复制大量的代码,实际上是复制所有的代码。简单地复制/粘贴整个类、重命名并向它们添加额外的字段就更容易了。
发布于 2010-08-15 19:22:46
我认为柯克·沃尔尔在评论中的想法是最好的选择。我在代码中遇到了类似的问题,我想出了同样的想法。您真正想要做的是拥有一个具有多重继承的继承树,并且在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继承)。如果“额外”内容不多,则只能复制额外的内容,即从Element继承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和ExtraDocument都有一个Extra类型的字段。您可以公开此字段,也可以为其所有功能编写一行重定向方法。鉴于缺乏多重继承,这确实是最低限度的重复。
发布于 2010-09-13 14:59:52
您可以尝试使用混合蛋白样构造来共享必要的代码:
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 { }您可以创建不同的混合器以获得不同的共享粒度。
https://stackoverflow.com/questions/3488103
复制相似问题