Json.Net返回空括号 [英] Json.Net returns Empty Brackets

查看:97
本文介绍了Json.Net返回空括号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有Node Class

I have Node Class

public Node<T> Parent { get; private set; }
public T Value { get; set; }
private readonly List<Node<T>> _children = new List<Node<T>>();

public Node(T value)
{
    Value = value;
}

public Node<T> this[int index]
{
    get
    {
        return _children[index];
    }
}

public Node<T> Add(T value, int index = -1)
{
    var childNode = new Node<T>(value);
    Add(childNode, index);
    return childNode;
}

public void Add(Node<T> childNode, int index = -1)
{
    if (index < -1)
    {
        throw new ArgumentException("The index can not be lower then -1");
    }
    if (index > Children.Count() - 1)
    {
        throw new ArgumentException("The index ({0}) can not be higher then index of the last iten. Use the AddChild() method without an index to add at the end".FormatInvariant(index));
    }
    if (!childNode.IsRoot)
    {
        throw new ArgumentException("The child node with value [{0}] can not be added because it is not a root node.".FormatInvariant(childNode.Value));
    }

    if (Root == childNode)
    {
        throw new ArgumentException("The child node with value [{0}] is the rootnode of the parent.".FormatInvariant(childNode.Value));
    }

    if (childNode.SelfAndDescendants.Any(n => this == n))
    {
        throw new ArgumentException("The childnode with value [{0}] can not be added to itself or its descendants.".FormatInvariant(childNode.Value));
    }
    childNode.Parent = this;
    if (index == -1)
    {
        _children.Add(childNode);
    }
    else
    {
        _children.Insert(index, childNode);
    }
}

public Node<T> AddFirstChild(T value)
    {
        var childNode = new Node<T>(value);
        AddFirstChild(childNode);
        return childNode;
    }

    public void AddFirstChild(Node<T> childNode)
    {
        Add(childNode, 0);
    }

    public Node<T> AddFirstSibling(T value)
    {
        var childNode = new Node<T>(value);
        AddFirstSibling(childNode);
        return childNode;
    }

    public void AddFirstSibling(Node<T> childNode)
    {
        Parent.AddFirstChild(childNode);
    }
    public Node<T> AddLastSibling(T value)
    {
        var childNode = new Node<T>(value);
        AddLastSibling(childNode);
        return childNode;
    }

    public void AddLastSibling(Node<T> childNode)
    {
        Parent.Add(childNode);
    }

    public Node<T> AddParent(T value)
    {
        var newNode = new Node<T>(value);
        AddParent(newNode);
        return newNode;
    }

    public void AddParent(Node<T> parentNode)
    {
        if (!IsRoot)
        {
            throw new ArgumentException("This node [{0}] already has a parent".FormatInvariant(Value), "parentNode");
        }
        parentNode.Add(this);
    }

    public IEnumerable<Node<T>> Ancestors
    {
        get
        {
            if (IsRoot)
            {
                return Enumerable.Empty<Node<T>>();
            }
            return Parent.ToIEnumarable().Concat(Parent.Ancestors);
        }
    }

    public IEnumerable<Node<T>> Descendants
    {
        get
        {
            return SelfAndDescendants.Skip(1);
        }
    }


    public IEnumerable<Node<T>> Children
    {
        get
        {
            return _children;
        }
    }

    public IEnumerable<Node<T>> Siblings
    {
        get
        {
            return SelfAndSiblings.Where(Other);

        }
    }

    private bool Other(Node<T> node)
    {
        return !ReferenceEquals(node, this);
    }

    public IEnumerable<Node<T>> SelfAndChildren
    {
        get
        {
            return this.ToIEnumarable().Concat(Children);
        }
    }

    public IEnumerable<Node<T>> SelfAndAncestors
    {
        get
        {
            return this.ToIEnumarable().Concat(Ancestors);
        }
    }

    public IEnumerable<Node<T>> SelfAndDescendants
    {
        get
        {
            return this.ToIEnumarable().Concat(Children.SelectMany(c => c.SelfAndDescendants));
        }
    }

    public IEnumerable<Node<T>> SelfAndSiblings
    {
        get
        {
            if (IsRoot)
            {
                return this.ToIEnumarable();
            }
            return Parent.Children;

        }
    }

    public IEnumerable<Node<T>> All
    {
        get
        {
            return Root.SelfAndDescendants;
        }
    }


    public IEnumerable<Node<T>> SameLevel
    {
        get
        {
            return SelfAndSameLevel.Where(Other);

        }
    }

    public int Level
    {
        get
        {
            return Ancestors.Count();
        }
    }

    public IEnumerable<Node<T>> SelfAndSameLevel
    {
        get
        {
            return GetNodesAtLevel(Level);
        }
    }

    public IEnumerable<Node<T>> GetNodesAtLevel(int level)
    {
        return Root.GetNodesAtLevelInternal(level);
    }

    private IEnumerable<Node<T>> GetNodesAtLevelInternal(int level)
    {
        if (level == Level)
        {
            return this.ToIEnumarable();
        }
        return Children.SelectMany(c => c.GetNodesAtLevelInternal(level));
    }

    public Node<T> Root
    {
        get
        {
            return SelfAndAncestors.Last();
        }
    }

    public void Disconnect()
    {
        if (IsRoot)
        {
            throw new InvalidOperationException("The root node [{0}] can not get disconnected from a parent.".FormatInvariant(Value));
        }
        Parent._children.Remove(this);
        Parent = null;
    }

    public bool IsRoot
    {
        get { return Parent == null; }
    }

    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return _children.Values().GetEnumerator();
    }

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

    public IEnumerator<Node<T>> GetEnumerator()
    {
        return _children.GetEnumerator();
    }

    public override string ToString()
    {
        return Value.ToString();
    }

    public static IEnumerable<Node<T>> CreateTree<TId>(IEnumerable<T> values, Func<T, TId> idSelector, Func<T, TId?> parentIdSelector)
        where TId : struct
    {
        var valuesCache = values.ToList();
        if (!valuesCache.Any())
            return Enumerable.Empty<Node<T>>();
        T itemWithIdAndParentIdIsTheSame = valuesCache.FirstOrDefault(v => IsSameId(idSelector(v), parentIdSelector(v)));
        if (itemWithIdAndParentIdIsTheSame != null) // Hier verwacht je ook een null terug te kunnen komen
        {
            throw new ArgumentException("At least one value has the samen Id and parentId [{0}]".FormatInvariant(itemWithIdAndParentIdIsTheSame));
        }

        var nodes = valuesCache.Select(v => new Node<T>(v));
        return CreateTree(nodes, idSelector, parentIdSelector);

    }

    public static IEnumerable<Node<T>> CreateTree<TId>(IEnumerable<Node<T>> rootNodes, Func<T, TId> idSelector, Func<T, TId?> parentIdSelector)
        where TId : struct
    {
        var rootNodesCache = rootNodes.ToList();
        var duplicates = rootNodesCache.Duplicates(n => n).ToList();
        if (duplicates.Any())
        {
            throw new ArgumentException("One or more values contains {0} duplicate keys. The first duplicate is: [{1}]".FormatInvariant(duplicates.Count, duplicates[0]));
        }

        foreach (var rootNode in rootNodesCache)
        {
            var parentId = parentIdSelector(rootNode.Value);
            var parent = rootNodesCache.FirstOrDefault(n => IsSameId(idSelector(n.Value), parentId));

            if (parent != null)
            {
                parent.Add(rootNode);
            }
            else if (parentId != null)
            {
                throw new ArgumentException("A value has the parent ID [{0}] but no other nodes has this ID".FormatInvariant(parentId.Value));
            }
        }
        var result = rootNodesCache.Where(n => n.IsRoot);
        return result;
    }


    protected static bool IsSameId<TId>(TId id, TId? parentId)
        where TId : struct
    {
        return parentId != null && id.Equals(parentId.Value);
    }

    #region Equals en ==

    public static bool operator ==(Node<T> value1, Node<T> value2)
    {
        if ((object)(value1) == null && (object)value2 == null)
        {
            return true;
        }
        return ReferenceEquals(value1, value2);
    }

    public static bool operator !=(Node<T> value1, Node<T> value2)
    {
        return !(value1 == value2);
    }

    public override bool Equals(Object anderePeriode)
    {
        var valueThisType = anderePeriode as Node<T>;
        return this == valueThisType;
    }

    public bool Equals(Node<T> value)
    {
        return this == value;
    }

    public bool Equals(Node<T> value1, Node<T> value2)
    {
        return value1 == value2;
    }

    bool IEqualityComparer.Equals(object value1, object value2)
    {
        var valueThisType1 = value1 as Node<T>;
        var valueThisType2 = value2 as Node<T>;

        return Equals(valueThisType1, valueThisType2);
    }

    public int GetHashCode(object obj)
    {
        return GetHashCode(obj as Node<T>);
    }

    public override int GetHashCode()
    {
        return GetHashCode(this);
    }

    public int GetHashCode(Node<T> value)
    {
        return base.GetHashCode();
    }
    #endregion
}

并且在Controller中,我尝试将此类列表格式化为Json

and in Controller I Try To format this class list to Json

var treeView = Node<ControlType>.CreateTree(_controlTypeBll.GetAll(), c => c.Id, c => c.ParrentId);

var res = JsonConvert.SerializeObject(treeView);

,我在res变量中获得的所有内容都是"[[],[],[[] []] ....".我使用了DataContract和DataMember属性来防止序列化某些属性,但结果是相同的

and All I Get in res variable is this " [[],[],[[][]]....". I have used DataContract and DataMember Attribute to Prevent Serializing some properties but the result is same

推荐答案

您的问题不包括您的Node<T>类的声明.在其他(大型)类中,我认为它一定是这样的:

Your question does not include the declaration of your Node<T> class. From the rest of the (large) class, I reckon it must be something like:

public class Node<T> : IEqualityComparer, IEnumerable<T>

这说明了您的问题:

  1. 您的课程为某些T实现IEnumerable<T>.
  2. Json.NET 将任何IEnumerable序列化为JSON数组
  3. JSON数组(根据标准)不支持命名属性.
  4. 因此,您的Value属性未序列化.
  1. Your class implements IEnumerable<T> for some T.
  2. Json.NET serializes any IEnumerable as a JSON array.
  3. JSON arrays (according to the standard) do not support named properties.
  4. Thus your Value property is not serialized.

如果您希望继续使Node<T>工具实现IEnumerable,则需要创建一个自定义 JsonConverter :

If you wish to continue making your Node<T> implement IEnumerable, you need to create a custom JsonConverter for it:

public static class TypeExtensions
{
    public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
    {
        while (type != null)
        {
            yield return type;
            type = type.BaseType;
        }
    }
}

public class NodeConverter : JsonConverter
{
    class NodeWrapper<T>
    {
        public T value { get; set; }
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public IEnumerable<Node<T>> children { get; set; }
    }

    static Type GetNodeValueType(Type type)
    {
        return type.BaseTypesAndSelf().Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Node<>)).Select(t => t.GetGenericArguments()[0]).FirstOrDefault();
    }

    public override bool CanConvert(Type objectType)
    {
        return GetNodeValueType(objectType) != null;
    }

    object ReadJsonGeneric<T>(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var wrapper = serializer.Deserialize<NodeWrapper<T>>(reader);
        if (wrapper == null)
            return existingValue;
        var node = existingValue as Node<T> ?? new Node<T>(wrapper.value);
        node.Value = wrapper.value;
        if (wrapper.children != null)
            foreach (var child in wrapper.children)
                node.Add(child);
        return node;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var method = GetType().GetMethod("ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
        var genericMethod = method.MakeGenericMethod(new[] { GetNodeValueType(objectType) });
        return genericMethod.Invoke(this, new object[] { reader, objectType, existingValue, serializer });
    }

    void WriteJsonGeneric<T>(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var node = (Node<T>)value;
        serializer.Serialize(writer, new NodeWrapper<T> { value = node.Value, children = (node.Children.Any() ? node.Children : null)});
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var method = GetType().GetMethod("WriteJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
        var genericMethod = method.MakeGenericMethod(new[] { GetNodeValueType(value.GetType()) });
        genericMethod.Invoke(this, new object[] { writer, value, serializer });
    }
}

通过调用您的Add(Node<T> child)方法,转换器还可以确保设置了父级后向引用.

By calling your Add(Node<T> child) method, the converter also makes sure the parent back-references are set.

然后像这样使用它:

[JsonConverter(typeof(NodeConverter))]
public class Node<T> : IEqualityComparer, IEnumerable<T>
{

这篇关于Json.Net返回空括号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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