Deserializing public property with non-public setter in json.net

后端 未结 3 894
栀梦
栀梦 2020-12-10 16:13

Suppose I have the following class -

public class A 
{        
   public int P1 { get; internal set; }
}

Using json.net, I am able to seria

相关标签:
3条回答
  • 2020-12-10 16:25

    This is my solution to handle in more general case:

    class CustomResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty result = base.CreateProperty(member, memberSerialization);
    
            var propInfo = member as PropertyInfo;
            result.Writable |= propInfo != null 
                 && propInfo.CanWrite
                 && !propInfo.IsPrivate;
    
            return result;
        }
    }
    

    With class CInternalSetter:

    class CInternalSetter
    {
        public CInternalSetter()
        {
            LoggedEmployeeId3 = 10;
        }
        public int LoggedEmployeeId { get; set; }
        public int LoggedEmployeeId2 { get; internal set; }
        public int LoggedEmployeeId3 { get; }
        public override string ToString()
        {
            return JsonConvert.SerializeObject(this, Formatting.Indented);
        }
    }
    

    Then test it with against this class:

    JsonSerializerSettings settings = new JsonSerializerSettings();
    settings.ContractResolver = new CustomResolver();
    
    var c = new CInternalSetter()
    {
        LoggedEmployeeId = 1,
        LoggedEmployeeId2 = 2
    };
    
    var cString = JsonConvert.SerializeObject(c);
    
    Console.WriteLine(cString);
    Console.WriteLine(JsonConvert.DeserializeObject<CInternalSetter>(cString).ToString());
    Console.WriteLine("-------------------------------------------");
    Console.WriteLine(JsonConvert.DeserializeObject<CInternalSetter>(cString, settings).ToString());
    
    0 讨论(0)
  • 2020-12-10 16:33

    After some experimenting, I've found that a property is deserialised correctly if you decorate your property with:

    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)] 
    

    Applying to the class in the original question:

    public class A 
    {
       [JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)]        
       public int P1 { get; internal set; }
    }
    
    0 讨论(0)
  • 2020-12-10 16:38

    Yes, you can use a custom ContractResolver to make the internal property writable to Json.Net. Here is the code you would need:

    class CustomResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty prop = base.CreateProperty(member, memberSerialization);
    
            if (member.DeclaringType == typeof(A) && prop.PropertyName == "P1")
            {
                prop.Writable = true;
            }
    
            return prop;
        }
    }
    

    To use the resolver, create an instance of JsonSerializerSettings and set its ContractResolver property to a new instance of the custom resolver. Then, pass the settings to JsonConvert.DeserializeObject<T>().

    Demo:

    class Program
    {
        static void Main(string[] args)
        {
            string json = @"{ ""P1"" : ""42"" }";
    
            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.ContractResolver = new CustomResolver();
    
            A a = JsonConvert.DeserializeObject<A>(json, settings);
    
            Console.WriteLine(a.P1);
        }
    }
    

    Output:

    42
    

    Fiddle: https://dotnetfiddle.net/1fw2lC

    0 讨论(0)
提交回复
热议问题