Json.Net返回空括号 [英] Json.Net returns Empty Brackets
问题描述
我有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>
这说明了您的问题:
- 您的课程为某些
T
实现IEnumerable<T>
. - Json.NET 将任何
IEnumerable
序列化为JSON数组 - JSON数组(根据标准)不支持命名属性.
- 因此,您的
Value
属性未序列化.
- Your class implements
IEnumerable<T>
for someT
. - Json.NET serializes any
IEnumerable
as a JSON array. - JSON arrays (according to the standard) do not support named properties.
- 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屋!