使用部分类在C#中模拟C ++友谊

时间:2014-07-17 21:04:32

标签: c# partial-classes

我有以下情况:

我需要创建一个树状结构,一旦实例化,就是不可变的。例如,列出一个列表方法列表。问题是在构造过程中,我需要能够插入节点。所以我需要某种允许插入节点的私有接口,而这种结构的公共接口只允许检索它们。我试过这个:

public partial class TreeLike {
  public SomeType1 SomeTreeProperty1 { get; private set; }
  public SomeType2 SomeTreeProperty2 { get; private set; }

  private List<NodeLike> _Nodes = new List<NodeLike>();
  public ReadOnlyCollection<NodeLike> Nodes {
    get {
      return _Nodes.AsReadOnly();
    }
  }
}

public class NodeLike {
  public SomeType1 SomeNodeProperty { get; private set; }

  private List<NodeLike> _Children = new List<NodeLike>();
  public ReadOnlyCollection<NodeLike> Children {
    get {
      return _Children.AsReadOnly();
    }
  }

  public partial class TreeLike {
    public SomeType3 SomeTreeProperty3 { get; private set; }

    TreeLike() {
      NodeLike n0 = new NodeLike();
      NodeLike n1 = new NodeLike();
      n0._Children.Add(n1);
      _Nodes.Add(n0);
    }
  }
}

这个问题(除了在TreeLike内继续NodeLike的声明/定义)有点hackysh外观,是在它工作时SomeTreeProperty3 TreeLike 1}}对外界不可见。也就是说,如果我在最外层范围内创建TreeLike的实例,我只能访问第一个在&#34; global&#34;中声明的属性。部分类的范围声明。

所以我想知道是否有方法在分区类的嵌套延续中声明属性和方法仍然对全局范围(因此,此类的客户端)可见。或者如果没有,那么更好的C#-idiomatic方式是什么呢? 也许创建类的不可变版本?

2 个答案:

答案 0 :(得分:1)

您应该只在构造函数中执行所有初始化,因为它允许您使用只读字段实现真正的不变性。

例如,如果您的节点接口定义如下:

interface INode
{
    public string Name { get; }
    public ReadOnlyCollection<INode> Children { get; }
}

然后一个实现应该只是:

class Node : INode
{
    private readonly string _name;
    public string Name
    {
        get { return _name; }
    }

    private readonly ReadOnlyCollection<INode> _children;
    public ReadOnlyCollection<INode> Children
    {
        get { return _children; }
    }

    public Node(string name, IEnumerable<INode> children)
    {
        _name = name;
        _children = new List<INode>(children).AsReadOnly();
    }

    public Node(string name, params INode[] children)
        : this(name, (IEnumerable<INode>)children)
    { }
}

最后一个构造函数重载使用params关键字允许您直接通过构造函数传递子节点,这意味着您可以执行此操作:

var root = new Node(
    "root",
    new Node("left",
        new Node("left-left"),
        new Node("left-right")),
    new Node("right",
        new Node("right-left"),
        new Node("right-right"))
    );

答案 1 :(得分:0)

您的设计要求的可能解决方案可能看起来像这样:

public partial class TreeLike {
    public SomeType1 SomeTreeProperty1 { get; private set; }
    public SomeType2 SomeTreeProperty2 { get; private set; }
    public SomeType3 SomeTreeProperty3 { get; private set; }

    private List<NodeLike> _Nodes = new List<NodeLike>();
    public ReadOnlyCollection<NodeLike> Nodes {
        get {
            return _Nodes.AsReadOnly();
        }
    }

    TreeLike() {
        NodeLike n1 = new NodeLike();
        NodeLike n0 = new NodeLike(n1);

        _Nodes.Add(n0);
    }
}

public class NodeLike {
    public SomeType1 SomeNodeProperty { get; private set; }

    private List<NodeLike> _Children = new List<NodeLike>();
    public ReadOnlyCollection<NodeLike> Children {
        get {
            return _Children.AsReadOnly();
    }

    public NodeLike(params NodeLike[] children) {
        _Children = children.ToList();
    }
}

partial与此问题无关。 params是一种有用的语法,可以让您执行以下操作:

new NodeLike(childNode1, childNode2, childNode3);

旁注:埃及文章是discouraged in C#