如何将此IEnumerable <t>序列化为JSON? (DnnApiController)

时间:2018-02-20 14:45:11

标签: c# generics serialization ienumerable icollection

问题

我遇到的问题是,在构建它之后返回“treeNode”时,它在通过API向下发送时不会序列化。对象[和嵌套元素]在调试时看起来很棒,但是当浏览器接收到树的数据时,它会转换为空数组(当有更深层嵌套的子节点时,某些数组具有正确的长度)。任何帮助表示赞赏,请参阅下面的代码和输出。

运行:

TreeNode<GenericClass> treeNode = new TreeNode<GenericClass>(new GenericClass() { Title = "Root", URL = null });
GenericClass Google = new GenericClass() { Title = "Google", URL = "https://www.google.com" };
GenericClass Yahoo = new GenericClass() { Title = "Yahoo", URL = "https://www.yahoo.com" };
GenericClass Bing = new GenericClass() { Title = "Bing", URL = "https://www.bing.com" };
treeNode.AddChild(Google);
treeNode.AddChild(Yahoo);
treeNode.AddChild(Bing);
// return treeNode.ToString(); <- Doesnt work
// return treeNode.ToList(); <- Doesnt work
// return JsonConvert.SerializeObject(treeNode); <-Doesnt work
return treeNode;

TreeNode(树/层次结构构建类):

public class TreeNode<T> : IEnumerable<TreeNode<T>>
{
    #region Properties
    public T Data { get; set; }
    public TreeNode<T> Parent { get; set; }
    public ICollection<TreeNode<T>> Children { get; set; }
    public Boolean IsRoot
    {
        get { return Parent == null; }
    }
    public Boolean IsLeaf
    {
        get { return Children.Count == 0; }
    }
    public int Level
    {
        get
        {
            if (this.IsRoot)
            {
                return 0;
            }
            return Parent.Level + 1;
        }
    }
    #endregion

    public TreeNode(T data)
    {
        this.Data = data;
        this.Children = new LinkedList<TreeNode<T>>();
        this.ElementsIndex = new LinkedList<TreeNode<T>>();
        this.ElementsIndex.Add(this);
    }

    public TreeNode<T> AddChild(T child)
    {
        TreeNode<T> childNode = new TreeNode<T>(child) { Parent = this };
        this.Children.Add(childNode);
        this.RegisterChildForSearch(childNode);
        return childNode;
    }

    public override string ToString()
    {
        return Data != null ? Data.ToString() : "[data null]";
    }

    private ICollection<TreeNode<T>> ElementsIndex { get; set; }

    private void RegisterChildForSearch(TreeNode<T> node)
    {
        ElementsIndex.Add(node);
        if (Parent != null)
        {
            Parent.RegisterChildForSearch(node);
        } 
    }

    public TreeNode<T> FindTreeNode(Func<TreeNode<T>, bool> predicate)
    {
        return this.ElementsIndex.FirstOrDefault(predicate);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public IEnumerator<TreeNode<T>> GetEnumerator()
    {
        yield return this;
        foreach (var directChild in this.Children)
        {
            foreach (var anyChild in directChild)
            {
                yield return anyChild;
            }  
        }
    }
}

输出(序列化前):

enter image description here 输出(序列化后):

enter image description here

2 个答案:

答案 0 :(得分:2)

IEnumerator实施中,您有

yield return this;

这对我没有意义。

JSON.Net正在返回

  

Newtonsoft.Json.JsonSerializationException:自引用循环   检测

因为它很快就会检测到.Net将返回StackOverflowException。这个JSON看起来怎么样?

超越原始问题的范围,为什么不应该像这样实施GetEnumerator函数?

public IEnumerator<TreeNode<T>> GetEnumerator()
{
    return this.Children.GetEnumerator()
}

从最初的一眼看,你的代码看起来就像是在计算孩子,而不是孩子。

最简单的方法是调试序列化过程。 (没有自我参考,可能需要一段时间。)

答案 1 :(得分:0)

*适合我的解决方案

<强>运行:

TreeNode<GenericClass> treeNode = new TreeNode<GenericClass>(new GenericClass() { Title = "Root", URL = null });
GenericClass Google = new GenericClass() { Title = "Google", URL = "https://www.google.com" };
GenericClass Yahoo = new GenericClass() { Title = "Yahoo", URL = "https://www.yahoo.com" };
GenericClass Bing = new GenericClass() { Title = "Bing", URL = "https://www.bing.com" };
treeNode.AddChild(Google);
treeNode.AddChild(Yahoo);
treeNode.AddChild(Bing);
return JsonConvert.SerializeObject(treeNode, Formatting.Indented, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });

TreeNode类:

public class TreeNode<T>
{
    #region Properties
    public T Data { get; set; }
    public TreeNode<T> Parent { get; set; }
    public ICollection<TreeNode<T>> Children { get; set; }
    public Boolean IsRoot
    {
        get { return Parent == null; }
    }
    public Boolean IsLeaf
    {
        get { return Children.Count == 0; }
    }
    public int Level
    {
        get
        {
            if (this.IsRoot)
            {
                return 0;
            }
            return Parent.Level + 1;
        }
    }
    #endregion

    public TreeNode(T data)
    {
        this.Data = data;
        this.Children = new LinkedList<TreeNode<T>>();
        this.ElementsIndex = new LinkedList<TreeNode<T>>();
        this.ElementsIndex.Add(this);
    }

    public TreeNode<T> AddChild(T child)
    {
        TreeNode<T> childNode = new TreeNode<T>(child) { Parent = this };
        this.Children.Add(childNode);
        this.RegisterChildForSearch(childNode);
        return childNode;
    }

    public override string ToString()
    {
        return Data != null ? Data.ToString() : "[data null]";
    }

    private ICollection<TreeNode<T>> ElementsIndex { get; set; }

    private void RegisterChildForSearch(TreeNode<T> node)
    {
        ElementsIndex.Add(node);
        if (Parent != null)
        {
            Parent.RegisterChildForSearch(node);
        } 
    }

    public TreeNode<T> FindTreeNode(Func<TreeNode<T>, bool> predicate)
    {
        return this.ElementsIndex.FirstOrDefault(predicate);
    }
}

<强>返回:

{
  "Data": {
    "Title": "Root",
    "URL": null
  },
  "Parent": null,
  "Children": [
    {
      "Data": {
        "Title": "Google",
        "URL": "https://www.google.com"
      },
      "Children": [],
      "IsRoot": false,
      "IsLeaf": true,
      "Level": 1
    },
    {
      "Data": {
        "Title": "Yahoo",
        "URL": "https://www.yahoo.com"
      },
      "Children": [],
      "IsRoot": false,
      "IsLeaf": true,
      "Level": 1
    },
    {
      "Data": {
        "Title": "Bing",
        "URL": "https://www.bing.com"
      },
      "Children": [],
      "IsRoot": false,
      "IsLeaf": true,
      "Level": 1
    }
  ],
  "IsRoot": true,
  "IsLeaf": false,
  "Level": 0
}