开发者

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

开发者 https://www.devze.com 2023-03-05 01:35 出处:网络
This question already has an answer here: Getting SerializeObject to use JsonProperty "name" defined inside interface
This question already has an answer here: Getting SerializeObject to use JsonProperty "name" defined inside interface (1 answer) Closed 3 years ago.
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 = NullVal开发者_如何学运维ueHandling.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}?


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


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

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号