更新时间:2021-12-23 21:56:37
如果我使用这样定义的对象:
If I use objects defined like this:
public enum EntityType { Child1, Child2 };
abstract class ParentObject
{
public EntityType et { get; set; }
}
class ChildClass : ParentObject
{
public int ChildClassProp { get; set; }
public ChildClass()
{
this.et = EntityType.Child1;
}
}
class ChildClass2 : ParentObject
{
public int ChildClass2Prop { get; set; }
public ChildClass2()
{
this.et = EntityType.Child2;
}
}
然后我可以像这样愉快地反序列化派生类(ChildClass
和ChildClass2
)到ParentObject
:
Then I can happily deserialize derived classes(ChildClass
and ChildClass2
) to ParentObject
like this:
JsonSerializerSettings JSsettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
};
List<ParentObject> list = new List<ParentObject>();
list.Add(new ChildClass() { ChildClassProp = 1 });
list.Add(new ChildClass2() { ChildClass2Prop = 2 });
string message = JsonConvert.SerializeObject(list,
Newtonsoft.Json.Formatting.Indented, JSsettings);
list = JsonConvert.DeserializeObject<List<ParentObject>>(message, JSsettings);
message
的位置如下:
[
{
"$type": "ConsoleApplication4.ChildClass, ConsoleApplication4",
"ChildClassProp": 1,
"et": 0
},
{
"$type": "ConsoleApplication4.ChildClass2, ConsoleApplication4",
"ChildClass2Prop": 2,
"et": 1
}
]
此键的关键是使用TypeNameHandling = TypeNameHandling.Auto
进行序列化和反序列化.使用TypeNameHandling.Arrays
创建一条如下所示的消息:
The key in this one was using TypeNameHandling = TypeNameHandling.Auto
for both serialization and deserialization. Using TypeNameHandling.Arrays
creates a message that looks like this:
{
"$type": "System.Collections.Generic.List`1[[ConsoleApplication4.ParentObject, ConsoleApplication4]], mscorlib",
"$values": [
{
"ChildClassProp": 1,
"et": 0
},
{
"ChildClass2Prop": 2,
"et": 1
}
]
}
请注意,不包括列表项的类型,仅包括列表的类型,因此会出现错误.
Note that the types of the list items are not included, only the type of the list, hence the error you were getting.
我认为,按照您想要的方式工作的最简单方法是定义一个像这样的简单类,该类充当要序列化的对象的薄包装:
I think the easiest way to get this working the way you want is to define a simple class like this one that acts as a thin wrapper around the object you are serializing:
class ObjectContainer
{
public object Data { get; set; }
}
然后,代码将如下所示(请注意对TypeNameHandling.Auto
的更改):
Then the code would look like this (note the change to TypeNameHandling.Auto
):
JsonSerializerSettings JSsettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
};
List<ParentObject> list = new List<ParentObject>();
list.Add(new ChildClass() { ChildClassProp = 1 });
list.Add(new ChildClass2() { ChildClass2Prop = 2 });
ObjectContainer container = new ObjectContainer()
{
Data = list
};
string message = JsonConvert.SerializeObject(container,
Newtonsoft.Json.Formatting.Indented, JSsettings);
var objectContainer = JsonConvert.DeserializeObject<ObjectContainer>(message, JSsettings);
if (objectContainer.Data is List<int>)
{
Console.Write("objectContainer.Data is List<int>");
}
else if (objectContainer.Data is List<ParentObject>)
{
Console.Write("objectContainer.Data is List<ParentObject>");
}
else if (objectContainer.Data is string)
{
Console.Write("objectContainer.Data is string");
}
我之所以选择这种方法,是因为Json.Net将负责几乎所有工作.只需调用非泛型JsonConvert.DeserializeObject
方法就可以了,但是您将需要做其他工作,因为此方法将返回JContainer
,而不是object
.
The reason I have gone for this approach is that Json.Net will take care of almost all the work. Simply calling the non-generic JsonConvert.DeserializeObject
method is fine, but you would then need to do additional work as this method returns a JContainer
, not an object
.