JSON Newtonsoft C# 反序列化不同类型的对象列表
JSON Newtonsoft C# Deserialize List of Objects of Different Types
我需要为现有的报告界面实现远程连接,这需要对数据进行序列化和反序列化 类。这是 类 和接口的简化版本:
public interface IBase
{
string Name { get; }
}
public interface IDerived1
{
int Value { get; }
}
public interface IDerived2
{
bool Value { get; }
}
public class Base : IBase
{
public string Name { get; protected set; }
}
public class Derived1 : Base, IDerived1
{
public int Value { get; protected set; }
}
public class Derived2 : Base, IDerived2
{
public bool Value { get; protected set; }
}
作为输入参数,我得到
IEnumerable<IBase> reportingData
因此此集合可能包含 'Derived1' 和 'Derived2' 的任意数量和实例组合。然后我像这样序列化集合:
string serialisedReportingData = JsonConvert.SerializeObject( reportingData );
这给了我这个例子:
[{"Value":11,"Name":"Product Number"},{"Value":false,"Name":"Output 1 Enabled"}]
显然,仅凭此数据,反序列化是不可能的,因为各个集合条目的类型不在 JSON 中。例如,我可以将类型作为 JSON 的一部分,或者提供额外的类型集合以供反序列化期间使用。
我之前使用 CustomCreationConverter 重载来处理
JsonConvert.DeserializeObject<IEnumerable<Ixxx>>( ... );
场景类型,但这仅适用于 IEnumerable 内部的单一接口类型。在上面的示例中,我有两个:IDerived1 和 IDerived2。
我的问题:
a) 我不确定如何编写处理多个接口类型的 CustomCreationConverter,我不知道如何将类型放入其中。
b) 我希望您能提供有关如何实施解决方案的建议,该解决方案可为我提供与作为输入收到的 'IEnumerable reportingData' 相同的反序列化输出。
如果可能,我将不胜感激。
非常感谢,
克里斯蒂安
更新:(灵感来自 dbc 的评论)
在使用类型名称反序列化时,您应该使用 SerializationBinder。
KnownTypesBinder 见此处。 (Newtonsoft.Json 需要大于 10 的版本)
首先,如果您想设置属性,则必须设置它们 public
。
然后你可以用一个JsonSerializerSettings
到Serialize/Deserialize.
List<IBase> loList = new List<IBase>();
loList.Add(new Base() { Name = "Base" });
loList.Add(new Derived1() { Name = "Derived1", Value = 3 });
loList.Add(new Derived2() { Name = "Derived2", Value = true });
KnownTypesBinder loKnownTypesBinder = new KnownTypesBinder()
{
KnownTypes = new List<Type> { typeof(Base), typeof(Derived1), typeof(Derived2) }
};
IEnumerable<IBase> reportingData = loList.AsEnumerable();
JsonSerializerSettings loJsonSerializerSettings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects,
SerializationBinder = loKnownTypesBinder
};
string lsOut = JsonConvert.SerializeObject(reportingData, loJsonSerializerSettings);
reportingData = JsonConvert.DeserializeObject<IEnumerable<IBase>>(lsOut, loJsonSerializerSettings);
如果您像那样使用 JsonSerializerSettings
,类型信息将包含在 json 字符串中。
[{
"$type": "Base",
"Name": "Base"
}, {
"$type": "Derived1",
"Value": 3,
"Name": "Derived1"
}, {
"$type": "Derived2",
"Value": true,
"Name": "Derived2"
}
]
我需要为现有的报告界面实现远程连接,这需要对数据进行序列化和反序列化 类。这是 类 和接口的简化版本:
public interface IBase
{
string Name { get; }
}
public interface IDerived1
{
int Value { get; }
}
public interface IDerived2
{
bool Value { get; }
}
public class Base : IBase
{
public string Name { get; protected set; }
}
public class Derived1 : Base, IDerived1
{
public int Value { get; protected set; }
}
public class Derived2 : Base, IDerived2
{
public bool Value { get; protected set; }
}
作为输入参数,我得到
IEnumerable<IBase> reportingData
因此此集合可能包含 'Derived1' 和 'Derived2' 的任意数量和实例组合。然后我像这样序列化集合:
string serialisedReportingData = JsonConvert.SerializeObject( reportingData );
这给了我这个例子:
[{"Value":11,"Name":"Product Number"},{"Value":false,"Name":"Output 1 Enabled"}]
显然,仅凭此数据,反序列化是不可能的,因为各个集合条目的类型不在 JSON 中。例如,我可以将类型作为 JSON 的一部分,或者提供额外的类型集合以供反序列化期间使用。
我之前使用 CustomCreationConverter 重载来处理
JsonConvert.DeserializeObject<IEnumerable<Ixxx>>( ... );
场景类型,但这仅适用于 IEnumerable 内部的单一接口类型。在上面的示例中,我有两个:IDerived1 和 IDerived2。
我的问题:
a) 我不确定如何编写处理多个接口类型的 CustomCreationConverter,我不知道如何将类型放入其中。
b) 我希望您能提供有关如何实施解决方案的建议,该解决方案可为我提供与作为输入收到的 'IEnumerable reportingData' 相同的反序列化输出。
如果可能,我将不胜感激。
非常感谢, 克里斯蒂安
更新:(灵感来自 dbc 的评论)
在使用类型名称反序列化时,您应该使用 SerializationBinder。 KnownTypesBinder 见此处。 (Newtonsoft.Json 需要大于 10 的版本)
首先,如果您想设置属性,则必须设置它们 public
。
然后你可以用一个JsonSerializerSettings
到Serialize/Deserialize.
List<IBase> loList = new List<IBase>();
loList.Add(new Base() { Name = "Base" });
loList.Add(new Derived1() { Name = "Derived1", Value = 3 });
loList.Add(new Derived2() { Name = "Derived2", Value = true });
KnownTypesBinder loKnownTypesBinder = new KnownTypesBinder()
{
KnownTypes = new List<Type> { typeof(Base), typeof(Derived1), typeof(Derived2) }
};
IEnumerable<IBase> reportingData = loList.AsEnumerable();
JsonSerializerSettings loJsonSerializerSettings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects,
SerializationBinder = loKnownTypesBinder
};
string lsOut = JsonConvert.SerializeObject(reportingData, loJsonSerializerSettings);
reportingData = JsonConvert.DeserializeObject<IEnumerable<IBase>>(lsOut, loJsonSerializerSettings);
如果您像那样使用 JsonSerializerSettings
,类型信息将包含在 json 字符串中。
[{
"$type": "Base",
"Name": "Base"
}, {
"$type": "Derived1",
"Value": 3,
"Name": "Derived1"
}, {
"$type": "Derived2",
"Value": true,
"Name": "Derived2"
}
]