本文介绍了如何从接口继承属性使用JSON.NET序列化时,它反对的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using Newtonsoft.Json.Serialization;
using System.Linq;
using System.Reflection;
public interface IParent
{
    [JsonProperty]
    int Id {get;set;}
}

[JsonObject(MemberSerialization.OptIn)]
public class Parent : IParent
{
    public int Id { get;set; }  
    public string Name {get;set;}   
}

public class Serializer
{
    public static void Main()
    {

        var parent = new Parent() { Id = 1, Name ="Parent"};        
        var sb = new StringBuilder();
                var sw = new StringWriter(sb);

                var settings = new JsonSerializerSettings()
                       {
                           NullValueHandling = NullValueHandling.Ignore                            
                       };

            var output = JsonConvert.SerializeObject(parent, Formatting.None, settings);
                Console.WriteLine(output);
            Console.ReadKey();
    }
}

在上面的代码,输出的 {} 。是否有可能要序列化,并得到输出的 {ID:1}?

In the above code, the output is {}. Is it possible to serialize and get the output as {"Id":1}?

推荐答案

这是一个坏主意

话虽如此,Newtonsoft提供了一种方法为你改变什么是序列化。在这种情况下,你会 DefaultContractResolver 并覆盖 CreateProperty

Having said that, Newtonsoft provides a way for you to change what's serialized: in this case, you'd subclass DefaultContractResolver and override CreateProperty.

现在的问题是,这是不容易的决定时,你应该选择加入基于接口的属性序列化。一方面,一类可能实现与冲突的系列化说明多个接口。此外,反序列化的对象放入声明为冲突的接口(例如)变量将无法工作。它是脆弱的,它是不是安全(它允许外部代码到指定一个实例揭示了什么数据)。

The problem is, it isn't easy to decide when you should opt-in to serialization based on an interface's attributes. For one thing, a class could potentially implement multiple interfaces with conflicting serialization instructions. Moreover, deserializing an object into a variable declared as a conflicting interface (for example) won't work. It's fragile and it isn't secure (it allows external code to specify what data an instance reveals).

如果你必须这样做,下面的代码适用于您的案例:

If you have to do it, the code below works for your case:

public class InterfaceContractResolver : DefaultContractResolver, IContractResolver
{
    public InterfaceContractResolver() : this(false) { }
    public InterfaceContractResolver(bool shareCache) : base (shareCache) {}

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        var interfaces = member.DeclaringType.GetInterfaces();
        foreach (var @interface in interfaces)
        {
            foreach (var interfaceProperty in @interface.GetProperties())
            {
                // This is weak: among other things, an implementation 
                // may be deliberately hiding an interface member
                if (interfaceProperty.Name == member.Name && interfaceProperty.MemberType == member.MemberType)
                {
                    if (interfaceProperty.GetCustomAttributes(typeof(JsonPropertyAttribute), true).Any())
                    {
                        property.Ignored = false;
                        return property;
                    }
                }
            }
        }
        return property;
    }

}



然后,当你创建您的序列化,通过它您的解析器的一个实例中的设置:

Then, when you're creating your serializer, pass it an instance of your resolver in the settings:

var settings = new JsonSerializerSettings()
{
    NullValueHandling = NullValueHandling.Ignore,
    ContractResolver = new InterfaceContractResolver(true)
};

这篇关于如何从接口继承属性使用JSON.NET序列化时,它反对的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-16 07:48