How to inherit the attribute from interface to object when serializing it using JSON.NET [duplicate]

感情迁移 提交于 2019-12-14 01:25:10

问题


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();
    }
}

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


回答1:


This is a bad idea.

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)
};



回答2:


See here...I do not believe that this works. JsonProperty attributes on the interface are ignored for the object that implements the interface.



来源:https://stackoverflow.com/questions/5951043/how-to-inherit-the-attribute-from-interface-to-object-when-serializing-it-using

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!