带有父/子循环引用的ServiceStack.Text StackOverflowException

时间:2015-04-08 14:14:31

标签: c# serialization stack-overflow servicestack-text

简单(1:1)父/子循环引用的序列化有效,如mythz answer here中所述。但是,当我尝试使用将ref保存回其父级的子级列表来序列化父级时,我收到了StackOverflowException。

我已经在GitHub上的commonGib回购中将其简化为teststest classes

试验:

/// <summary>
/// Trivial business classes with a simple 1:1 circular relationship, i.e. Parent.Child, Child.Parent.
/// </summary>
[TestMethod]
public void Simple_ServiceStack()
{
    var parent = new SimpleParent() { Text = "Foo" };
    var child = new SimpleChild() { Number = 2 };

    parent.Child = child;
    child.Parent = parent;

    var parentJson = JsonSerializer.SerializeToString(parent);

    var parentTest = JsonSerializer.DeserializeFromString<SimpleParent>(parentJson);

    Assert.IsTrue(parentTest.TextEqualsFoo());
    Assert.IsTrue(parentTest.Child.NumberEqualsTwo());
}

/// <summary>
/// Test business classes more complex by having a parent with a list of children, as opposed
/// to a 1:1 relationship, i.e. Parent.Children instead of Parent.Child.
/// </summary>
[TestMethod]
public void Complex_ServiceStack()
{
    var parent = new ComplexParent() { Text = "Foo" };
    var child = new ComplexChild() { Number = 2 };

    parent.Children = new List<ComplexChild>() { child };
    child.Parent = parent;

    var parentJson = JsonSerializer.SerializeToString(parent); //Throws stack overflow

    var parentTest = JsonSerializer.DeserializeFromString<ComplexParent>(parentJson);

    Assert.IsTrue(parentTest.TextEqualsFoo());
    foreach (var childTest in parentTest.Children)
    {
        Assert.IsTrue(childTest.NumberEqualsTwo());
    }
}

/// <summary>
/// Real-world business classes wrapped around a state class.
/// </summary>
[TestMethod]
public void VeryComplex_ServiceStack()
{
    var parentState = new VeryComplexParentState() { Text = "Foo" };
    var childState = new VeryComplexChildState() { Number = 2 };

    var parent = new VeryComplexParent() { State = parentState };
    var child = new VeryComplexChild() { State = childState };

    parent.Children = new List<VeryComplexChild>() { child };
    child.Parent = parent;

    var parentJson = JsonSerializer.SerializeToString(parent); //Throws stack overflow

    var parentTest = JsonSerializer.DeserializeFromString<ComplexParent>(parentJson);

    Assert.IsTrue(parentTest.TextEqualsFoo());
    foreach (var childTest in parentTest.Children)
    {
        Assert.IsTrue(childTest.NumberEqualsTwo());
    }
}

测试类:

#region Simple Parent/Child

public class SimpleParent
{
    public string Text { get; set; }
    public SimpleChild Child { get; set; }

    /// <summary>
    /// This is like a validation rule on the state wrapper.
    /// </summary>
    public bool TextEqualsFoo()
    {
        return Text == "Foo";
    }
}

public class SimpleChild
{
    public int Number { get; set; }
    public SimpleParent Parent { get; set; }

    /// <summary>
    /// This is like a validation rule on the state wrapper.
    /// </summary>
    public bool NumberEqualsTwo()
    {
        return Number == 2;
    }
}

#endregion

#region Complex Parent/Child

public class ComplexParent
{
    public string Text { get; set; }
    public List<ComplexChild> Children { get; set; }

    /// <summary>
    /// This is like a validation rule on the state wrapper.
    /// </summary>
    public bool TextEqualsFoo()
    {
        return Text == "Foo";
    }
}

public class ComplexChild
{
    public int Number { get; set; }
    public ComplexParent Parent { get; set; }

    /// <summary>
    /// This is like a validation rule on the state wrapper.
    /// </summary>
    public bool NumberEqualsTwo()
    {
        return Number == 2;
    }
}

#endregion

#region Very Complex Parent/Child

public abstract class BaseSerializationTestClass<TState>// : BaseSerializationTestClass
{
    public TState State { get; set; }
}


public class VeryComplexParent : BaseSerializationTestClass<VeryComplexParentState>
{
    /// <summary>
    /// This is like a validation rule on the state wrapper.
    /// </summary>
    public bool TextEqualsFoo()
    {
        return State != null && State.Text == "Foo";
    }

    public List<VeryComplexChild> Children { get; set; }
}

public class VeryComplexParentState
{
    public string Text { get; set; }

    public List<VeryComplexChildState> MyChildrenState { get; set; }
}

public class VeryComplexChild : BaseSerializationTestClass<VeryComplexChildState>
{
    /// <summary>
    /// This is like a validation rule on the state wrapper.
    /// </summary>
    public bool NumberEqualsTwo()
    {
        return State != null && State.Number == 2;
    }

    public VeryComplexParent Parent { get; set; }
}

public class VeryComplexChildState
{
    public int Number { get; set; }

    public VeryComplexParentState MyAState { get; set; }
}

#endregion

1 个答案:

答案 0 :(得分:1)

没有。循环引用不起作用。即使在您获得序列化的第一个示例(Simple_ServiceStack)中,我也得到了:

  

{&#34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34 ;:{&#34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; :{&#34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34 ;: {&#34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34;:{ &#34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34;:{& #34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&# 34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34 ;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本& #34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&# 34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34 ;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34;:{ &#34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34;:{& #34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&# 34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34 ;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本& #34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&# 34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34 ;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34; :&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34 ;: &#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:& #34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&# 34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34 ;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本& #34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&# 34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34 ;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34; :&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34 ;: &#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:& #34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&# 34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&#34 ;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&#34; FOO&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&#34;富& #34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;特克斯T&#34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本& #34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&# 34;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34 ;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34; :&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34 ;: &#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:& #34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&# 34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&#34 ;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&#34; FOO&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&#34;富& #34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34;:&#34;富&# 34;,&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#3 4;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34 ;:&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34; {&#34;文本&#34; :&#34;富&#34;&#34;儿童&#34; {&#34;数&#34;:2&#34;父&#34 ;:}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}

错误已损坏(请参阅上一篇"Parent":})。 (用ServiceStack.Text 4.0.38测试)

如其中一条评论所述:

  

您的示例dto未使用循环引用 - 它为每个链接属性使用不同的对象

根据您链接的问题的建议,将Json.NET与meta ID一起使用。