分层对象和自动修复 [英] Hierarchical object and AutoFixture

查看:100
本文介绍了分层对象和自动修复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实现了一个用于存储标签的类,标签集合必须是分层的,所以我的类是:

I have implemented a class for storing tags, the tag collection must be hierachical, and so my class is:

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.)
}

通过这种方式,根标记(用户希望能够拥有许多单独的树)没有父标记,而非根标记必须具有父标记.

In this way root tags (user want to be able to have many separate trees) has no parent, while non-root tags must have a parent tag.

  1. 这是实现层次结构的好方法吗?我找到了Composite Pattern,但是在我的域中,所有标签都是简单的标签,对于领域专家来说,父标签和子标签之间没有区别.

  1. Is this a good way to implement hierarchy? I find Composite Pattern, but in my domain, all tags are simply tags, to the domain expert, there is no difference between parent and child tag.

在测试中使用AutoFixture出现问题;当我需要创建一个简单标签时,会引发此错误:

Problem come using AutoFixture in test; when I need to create a simple tag, it raises this error:

失败:Ploeh.AutoFixture.ObjectCreationException:AutoFixture无法创建类型为Ploeh.AutoFixture.Kernel.SeededRequest的实例,因为所遍历的对象图包含循环引用.

Failure: Ploeh.AutoFixture.ObjectCreationException: AutoFixture was unable to create an instance of type Ploeh.AutoFixture.Kernel.SeededRequest because the traversed object graph contains a circular reference.

我读了使用AutoFixture创建递归树,但情况不同:我只有一个类,不是2,并且我不希望自动治具创建树,而只创建一个节点

i read Creating recursive tree with AutoFixture but it's different case: i have only one class, not 2 and i don't want autofixture to create a tree but only a single node

推荐答案

这是实现层次结构的好方法吗?

我看到它有三个问题,一个是小问题,一个是更严重的问题,另外一个在您的具体情况下显然有问题.

I see three problems with it, one minor, one a little more serious, and one obviously problematic in your concrete situation.

潜在问题:

1..让我们从一个小问题开始,该问题与属性名称及其类型之间的关系有关.我建议一个名为ParentTag的属性本身应为Tag类型.您将其声明为int的事实(就像您对Id所做的一样)表明您应该改为调用属性ParentTagId…或将属性的类型更改为Tag.

1. Let's start with the minor issue, which is about the relationship between properties' names and their types. I would recommend that a property named ParentTag should be of the Tag type itself. The fact that you declared it as int (like you did for Id) suggests that you should call the property ParentTagId instead… or that you change the property's type to Tag.

2..现在来看更严重的问题.我认为Desc指向直接子标记. (如果一个标签可以有多个子标签,则显然您为此属性选择了错误的类型.您需要某种收集.但这是另一个问题.)

2. Now to the more serious issue. I take it that Desc points to an immediate child tag. (In case that one tag can have more than one child tag, you have obviously chosen the wrong type for this property. You'd need some kind of collection. But that's yet another problem.)

如果不注意的话,同时存储父母和孩子的链接很容易导致不一致.因此,最好不要为每个标签都具有双向链接,而只存储一个方向上的链接.

Storing both parent and children links can easily lead to inconsistencies if you're not paying good attention. It might therefore be better not to have bi-directional links for each tag, but to only store links going in one direction.

然而,这将使在相反方向上遍历层次结构变得复杂.解决此问题的一种方法是仅存储子链接.如果您随后想找到 T 的父标签,则首先要通过从根标签开始递归遍历层次结构并持续跟踪" T "来找到 T .路径"你正在服用;则父级将成为路径中的倒数第二个标签.

That however will complicate traversing the hierarchy in the opposite direction. One way to solve this problem would be to store only child links; if you then wanted to find the parent tag of T, you'd first find T by recursively traversing the hierarchy starting at the root tag and continuously keep track of the "path" you're taking; the parent will then be the penultimate tag in the path.

3..现在是最直接的问题.异常提示了它:

3. Now to the most immediate issue. The exception hints at it:

Ploeh.AutoFixture.ObjectCreationException […],因为遍历的对象图包含循环引用.

使用当前的Tag实现,可以构建包含循环的标记层次结构.我以为你不想要那个.

With your current implementation of Tag, it's possible to build tag hierarchies that contain cycles. I assume that you don't want that.

例如,标签 C 可以将 P 作为其父标签,尽管 P 已经是 C .因此,如果您开始遵循从 C 开始的ParentTag链,您将首先到达 P ,然后最终回到 C ,如果继续前进,就会陷入无限循环.

For example, tag C can have P as its parent tag, although P is already a child tag of C. Therefore, if you started following the ParentTag chain starting at C, you would first get to P and then eventually arrive back at C, and if you kept going, you would find yourself caught in an infinite loop.

我不了解AutoFixture,但由于类似的原因,它似乎无法处理您的具体标签层次结构.

I don't know AutoFixture, but it seems likely that it cannot deal with your concrete tag hierarchy for similar reasons.

您应该使标签层次结构有向无环图(DAG) -非循环的"在这里很重要.但是,使用当前的Tag类,您可以构建任何有向图;它不能保证不会有任何循环.

You should make your tag hierarchies directed acyclic graphs (DAGs) — the "acyclic" is the important bit here. However, with your current Tag class, you can build any directed graph; it does not guarantee that there won't be any cycles.

防止循环标记层次结构的方法:

1..对ParentTag设置器中的循环进行检查:

1. Implement a check for cycles in the ParentTag setter:

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,这将迫使您在构造函数中进行设置.这将自动使其无法构建循环标记层次结构-如果您不相信,请尝试一下:

2. Even simpler, make ParentTag readonly, which forces you to set it in the constructor. This will automatically make it impossible to build cyclic tag hierarchies — try it, if you don't believe it:

public Tag(Tag parentTag)
{
    this.parentTag = parentTag;
}

private readonly Tag parentTag;

public Tag ParentTag
{
    get
    {
        return parentTag;
    }
}

我会推荐第二种解决方案.

I would recommend the second solution.

这篇关于分层对象和自动修复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆