问题
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