【发布时间】:2019-08-18 12:32:50
【问题描述】:
所以,我有一个类似于this one 的用例,但有一些额外的细节,我觉得需要提出一个新问题。 (relatedquestions,供参考)
我正在编写一个实现a cycle 的数据结构。基本设计是这样的:
public class Cycle<T>
{
public Node<T> Origin { get; private set; }
public int Count { get; private set; }
}
public class Node<T>
{
public Cycle<T> Cycle { get; private set; }
public Node<T> Next { get; private set; }
public Node<T> Previous { get; private set; }
public T Value { get; set; }
}
但是,我想实现以下所有行为:
- 在插入/删除节点时更新 Cycle.Count
- 允许“空”
Cycle(即Origin = null)为Origin创建一个新的Node - 防止在案例 1 和 2 之外构造新的
Node对象 - 避免暴露不需要由这两个以外的类调用的方法
在 C++ 中,我只需将每个类设为另一个类的 friend。但是在 C# 中,我看不到让它工作的方法。
我知道如果我将Node 嵌套在Cycle 内并且只为Node 公开一个构造函数,我可以实现除#3 之外的所有内容,如下所示:
public class Cycle<T>
{
public Node Origin { get; private set; }
public int Count { get; private set; }
public class Node
{
public Cycle<T> Cycle { get; private set; }
public Node Next { get; private set; }
public Node Previous { get; private set; }
public T Value { get; set; }
internal Node<T>(Cycle<T> cycle)
{
if (cycle.Origin != null)
throw new InvalidOperationException();
else
{
Cycle = cycle;
Next = this;
Previous = this;
cycle.Origin = this;
cycle.Count = 1;
}
}
}
}
但是如你所见,我只能到internal,所以我还是要验证数据完整性或者破坏封装。
我确实有一个“聪明”的想法,但这是一种黑魔法的答案:
public abstract class Cycle<T>
{
public Node Origin { get; private set; }
public int Count { get; private set; }
public sealed class Node
{
private CycleInternal _cycle;
public Cycle<T> Cycle { get { return _cycle; } }
public Node Next { get; private set; }
public Node Previous { get; private set; }
public T Value { get; set; }
// this constructor can be called by CycleInternal, but not other classes!
private Node(CycleInternal cycle)
{
Cycle = cycle;
Next = this;
Previous = this;
cycle.Origin = this;
cycle.Count = 1;
}
private sealed class CycleInternal : Cycle<T>
{
// this constructor can be called by Node, but not other classes!
public CycleInternal() {}
}
}
}
在这种情况下,我担心其他东西可以从 Cycle 继承;可以通过将构造函数设置为 Cycle 私有来防止这种情况吗?还是我只是在这里偏执?
【问题讨论】:
-
使用
internal有什么问题?您想阻止这里发生什么? -
也许我没有得到主题,但为什么在节点内有一个 Cycle 实例?你不是还需要一个 IEnumerable
> 在 Cycle 中吗? -
@Matthew
internal将它暴露给同一程序集中的其他类,我不想这样做。这是图书馆的一部分,我不想冒险任何事情我不需要。 @DavideVitali 每个Node都在跟踪它属于哪个Cycle,以便计算Cycle.Count,检查两个Nodes 是否属于同一个Cycle,并更轻松地更新Cycle.Origin.Cycle只需要引用一个节点就可以实现IEnumerable<Node<T>>本身。
标签: c# inner-classes encapsulation friend