为什么 Json.net 不能正确序列化从 TreeNode 派生的 class?

Why doesn't Json.net properly serialize a class derived from TreeNode?

我有一个从 TreeNode 继承的 class,当我尝试序列化它时,它只是 returns 一个不是 JSON 字符串的字符串(如我所料)。

例如:

string json = JsonConvert.SerializeObject(new A());

输出:

"TreeNode: "

其中 A 定义为:

public class A : TreeNode { public int x { get; set; } }

如果我删除 TreeNode 继承,输出为:

{"x":0}

如果它继承自 TreeNode,为什么它不序列化 属性? 注意:我过滤我的 class 以仅序列化我的 A class 的 public 属性,使用合同:

public class ShouldSerializeContractResolver : DefaultContractResolver
{
    private List<string> propertiesNames;

    public ShouldSerializeContractResolver(Type type)
    {
        this.propertiesNames =
            type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
            .Select(p => p.Name)
            .ToList();
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        property.ShouldSerialize =
            instance =>
            {
                return propertiesNames.Contains(property.PropertyName);
            };

        return property;
    }
}

然后使用以下方法序列化对象:

ShouldSerializeContractResolver contract = new ShouldSerializeContractResolver(typeof(CustomTreeNode));
            JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings() { ContractResolver = contract };
            string json = JsonConvert.SerializeObject(groups, Formatting.Indented, jsonSerializerSettings);

但它 returns 与我在主题开头提到的相同的无效输出。

如果您谈论的是应用于它的 System.Windows.Forms.TreeNode then the reason you are seeing this behavior is because TreeNode has a [TypeConverter] 属性,这会导致 Json.Net 将其序列化为简单的字符串值而不是对象。

您可以通过几种不同的方式让它按照您想要的方式工作。

  1. [JsonObject] 属性应用于您的自定义 TreeNode class

    [JsonObject]
    public class A : TreeNode
    { 
        ...
    }
    
  2. 或者,在您的自定义 ContractResolver 中覆盖 CreateContract() 方法,以便它为您的自定义类型显式创建一个对象契约:

    public class ShouldSerializeContractResolver : DefaultContractResolver
    {
        private Type myType;
        private List<string> propertiesNames;
    
        public ShouldSerializeContractResolver(Type type)
        {
            myType = type;
    
            this.propertiesNames =
                type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
                .Select(p => p.Name)
                .ToList();
        }
    
        protected override JsonContract CreateContract(Type objectType)
        {
            if (objectType == myType)
            {
                return CreateObjectContract(objectType);
            }
            return base.CreateContract(objectType);
        }
    
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty property = base.CreateProperty(member, memberSerialization);
    
            property.ShouldSerialize =
                instance =>
                {
                    return propertiesNames.Contains(property.PropertyName);
                };
    
            return property;
        }
    }