【问题标题】:How do I serialize this IEnumerable<T> to JSON? ( DnnApiController )如何将此 IEnumerable<T> 序列化为 JSON? (DnnApiController)
【发布时间】:2018-07-30 23:14:54
【问题描述】:

问题

我遇到的问题是,在构建后返回“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;
            }  
        }
    }
}

输出(序列化前):

输出(序列化后):

【问题讨论】:

  • 序列化怎么样?
  • 当你写return JsonConvert.SerializeObject(treeNode); doesn't work时,你说的不起作用是什么意思,有例外吗?或者,这会返回一个您不喜欢其格式的字符串吗?
  • 是的,它确实给出了异常 -> Newtonsoft.Json.JsonSerializationException:检测到类型为“TreeNode”的自引用循环

标签: c# generics serialization ienumerable icollection


【解决方案1】:

在您的 IEnumerator 实现中,您有一行

yield return this;

这对我来说没有意义。


JSON.Net 正在返回

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

因为它检测到很快 .Net 将返回 StackOverflowException。这个 JSON 看起来如何?


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

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

乍一看,您的代码似乎在枚举孙子,而不是子孙。

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

【讨论】:

  • 删除“yield return this;”时,“JsonConvert.Serialize(treeNode)”返回一个空数组。
  • 第一次迭代“yield return this;”返回父节点。第一次迭代后的 foreach 会返回孩子和他们的孩子等。
【解决方案2】:

*适合我的解决方案

跑步:

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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-08
    • 2015-07-19
    • 1970-01-01
    相关资源
    最近更新 更多