我已经实现了一个用于存储标记的类,标记集合必须是分级的,所以我的类是:
public class Tag
{
public int Id { get; set; }
public int Description { get; set; }
public Tag ParentTag { get; set; }
// … (methods for get children, add and remove children, etc.)
}这样,根标记(用户希望能够拥有多个独立的树)没有父标记,而非根标记必须有父标记。
Ploeh.AutoFixture.ObjectCreationException__:AutoFixture无法创建Ploeh.AutoFixture.Kernel.SeededRequest类型的实例,因为遍历的对象图包含一个循环引用。编辑:我读了用AutoFixture创建递归树,但情况不同:我只有一个类,而不是2个,我不希望自动夹具创建树,而只创建一个节点
发布于 2014-06-20 09:00:16
这是实现层次结构的好方法吗?
我看到了三个问题,一个小问题,一个更严重一点,和一个明显的问题,在你的具体情况。
潜在问题:
1.让我们从一个小问题开始,它涉及属性的名称和它们的类型之间的关系。我建议一个名为ParentTag的属性应该是Tag类型本身。您将其声明为int (与Id一样)的事实表明,您应该调用属性ParentTagId而不是…或者将属性的类型更改为Tag。
2.现在要谈到更严重的问题。我认为Desc指向一个直接的子标记。(如果一个标记可以有多个子标记,则显然为该属性选择了错误的类型。你需要一些收藏品。但这是另一个问题。)
存储父母和孩子的链接很容易导致不一致,如果你没有很好的注意。因此,最好不要为每个标签设置双向链接,而应该只存储一个方向的链接。
然而,这将使向相反方向遍历层次结构变得复杂。解决这个问题的一种方法是存储唯一的子链接;如果您想要找到T的父标记,那么首先通过递归遍历从根标记开始的层次结构来找到T,并不断地跟踪您所使用的“路径”;然后父标记将是路径中的倒数第二个标记。
3.现在是最直接的问题。例外情况暗示了这一点:
Ploeh.AutoFixture.ObjectCreationException…因为遍历的对象图包含一个循环引用。
使用Tag的当前实现,可以构建包含周期的标记层次结构。我猜你不想那样。
例如,标记C可以将P作为其父标记,尽管P已经是C的子标记。因此,如果您开始跟踪从C开始的ParentTag链,您将首先到达P,然后最终到达C,如果您继续运行,您会发现自己陷入了一个无限循环。
我不知道AutoFixture,但由于类似的原因,它可能无法处理具体的标记层次结构。
您应该使您的标记层次结构有向无圈图 -“无循环”是这里的重要部分。但是,使用当前的Tag类,您可以构建任何有向图;它不能保证不会有任何循环。
防止循环标记层次结构的方法:
1.在ParentTag设置器中实现了对周期的检查:
public Tag ParentTag
{
…
set
{
if (!IsOrIsAncestorOf(value))
{
parentTag = value;
}
else
{
throw new ArgumentException("ParentTag", "would cause a cycle");
}
}
}
private Tag parentTag;
private bool IsOrIsAncestorOf(Tag other)
{
return this == other || IsOrIsAncestorOf(other.Parent));
// ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Is … Or … IsAncestorOf
}2.甚至更简单,让ParentTag readonly,这迫使您在构造函数中设置它。这将自动使构建循环标记层次结构变得不可能--如果您不相信,尝试它:
public Tag(Tag parentTag)
{
this.parentTag = parentTag;
}
private readonly Tag parentTag;
public Tag ParentTag
{
get
{
return parentTag;
}
}我建议第二种解决办法。
https://stackoverflow.com/questions/24323300
复制相似问题