JsonSerializer behaves not as expected when the specifc class is casted to something else

a 夏天 提交于 2020-01-13 16:30:08

问题


Im trying to migrate from json.net to microsoft's json and found something that behaves very differently.

Let's use this simplified example:

public interface IName
{
    string Name { get; set; }

}

public class Person : IName
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public void Foo() 
{
   IName p = new Person {Age = 4, Name = "Waldo"};
   var s1 = System.Text.Json.JsonSerializer.Serialize(p); // --> {"Name":"Waldo"}
   var s2 = Newtonsoft.Json.JsonConvert.SerializeObject(p); // --> {"Name":"Waldo","Age":4}
}

Microsoft's Serializers serializes properties from IName JSON.NET serializes properties from Person

Is there a way to configure it so that it would work like JSON.NET? The options that I could pass do not indicate that this is configurable. Did I overlook something?


回答1:


This is because the serializer uses the type of the generic parameter, not the type of the passed value:

public static string Serialize<TValue>(TValue value, JsonSerializerOptions options = null)
{
    return WriteCoreString(value, typeof(TValue), options);
}

This passes typeof(IName) to WriteCoreString, and on that type ultimately reflection is performed.

You can work around this by explicitly passing the type to the overload that accepts that:

var s3 = System.Text.Json.JsonSerializer.Serialize(p, p.GetType());

This returns:

{"Name":"Waldo","Age":4}

Casting to object also works, as the code then calls value.GetType():

var s4 = System.Text.Json.JsonSerializer.Serialize((object)p);



回答2:


Newtonsoft.Json.JsonConvert.SerializeObject is a non-generic method so that it analyzes the provided object at runtime and serializes all properties that the object has.

In comparison System.Text.Json.JsonSerializer.Serialize(p) is resolved to a generic method. The compiler infers the type parameters based upon the type of the variable, in the case of your same IName. Therefore, the method analyzes the provided type and exports the properties of the generic type parameter, not all properties of the object that implements the interface.

The documentation shows that the serialize method always needs to be given a type, either through the generic type parameter or as a parameter to the method.

The following code should fixes the behavior:

var s1 = System.Text.Json.JsonSerializer.Serialize(p, p.GetType()); 
// --> {"Name":"Waldo","Age":4}

See this sample.




回答3:


Please see Serialize properties of derived classes

Polymorphic serialization isn't supported when you specify at compile time the type to be serialized.

(Examples here)

This behavior is intended to help prevent accidental exposure of data in a derived runtime-created type.

And then:

To serialize the properties of the derived type, use one of the following approaches:

  • Call an overload of Serialize that lets you specify the type at runtime:

    json = JsonSerializer.Serialize(weatherForecast, weatherForecast.GetType());

  • Declare the object to be serialized as object.

    json = JsonSerializer.Serialize<object>(weatherForecast);




回答4:


I think what you need is to pass the reference of the object to the method

        IName p = new Person { Age = 4, Name = "Waldo" };
        var s1 = System.Text.Json.JsonSerializer.Serialize<Person>((Person)p);

For .NET Core 3.0



来源:https://stackoverflow.com/questions/58429098/jsonserializer-behaves-not-as-expected-when-the-specifc-class-is-casted-to-somet

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