首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类推导问题

类推导问题
EN

Stack Overflow用户
提问于 2010-08-15 15:55:08
回答 2查看 145关注 0票数 0

我有以下三门课:

代码语言:javascript
复制
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 { }

我需要有一种方法来定义ExtraNodeExtraElementExtraDocument,这样它们就相当于复制上面的代码,在Node类中添加一些额外的字段,并在所有类的前缀中加上“额外”,如下所示:

代码语言:javascript
复制
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

那么,在不复制/粘贴整个文档并手动更改的情况下,实现这一目标的最佳方法是什么呢?我需要这样做不止一次。

编辑:为了澄清我需要做什么,我需要以下代码才能工作:

代码语言:javascript
复制
// this should accept an ExtraNode, an ExtraElement or an ExtraDocument:
void doSomethingWithANode(ExtraNode extraNode) { ... }

编辑2: Kirk关于实现接口的建议(如Timwi的代码所示)在我的例子中是不切实际的,因为每个类都有许多字段和方法(总共大约有8个类),所以我必须为每个“额外”派生组复制每个类。例如,Node类的外观如下:

代码语言:javascript
复制
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种方法。这也适用于其他所有的类。通过这种方法,我会复制大量的代码,实际上是复制所有的代码。简单地复制/粘贴整个类、重命名并向它们添加额外的字段就更容易了。

EN

回答 2

Stack Overflow用户

发布于 2010-08-15 19:22:46

我认为柯克·沃尔尔在评论中的想法是最好的选择。我在代码中遇到了类似的问题,我想出了同样的想法。您真正想要做的是拥有一个具有多重继承的继承树,并且在C#中只有接口允许这样做。

代码语言:javascript
复制
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 { ... }

现在,您想要的所有属性都是真的:

代码语言:javascript
复制
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)继承等等。

关于你在这里提到的问题:

代码语言:javascript
复制
public INode Parent { get; } // THIS IS WRONG, THIS SHOULD BE ExtraNode NOT INode

我认为这应该是IExtraNode。您可以通过使用一个显式实现的属性来解决这个问题(我现在假设您不是从ExtraNode派生Node,只是为了说明解决方案):

代码语言:javascript
复制
// 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的类,它包含所有额外的功能,并且ExtraNodeExtraElementExtraDocument都有一个Extra类型的字段。您可以公开此字段,也可以为其所有功能编写一行重定向方法。鉴于缺乏多重继承,这确实是最低限度的重复。

票数 1
EN

Stack Overflow用户

发布于 2010-09-13 14:59:52

您可以尝试使用混合蛋白样构造来共享必要的代码:

代码语言:javascript
复制
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 { }

您可以创建不同的混合器以获得不同的共享粒度。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3488103

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档