JSON Newtonsoft C# 反序列化不同类型的对象列表

Chr*_*ian 5 c# json.net json-deserialization

我需要为现有的报告接口实现远程连接,这需要数据类的序列化和反序列化。这是类和接口的简化版本:

    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; }
    }
Run Code Online (Sandbox Code Playgroud)

作为输入参数我得到

IEnumerable<IBase> reportingData
Run Code Online (Sandbox Code Playgroud)

因此,该集合可以包含任意数量的“Derived1”和“Derived2”实例及其组合。然后我像这样序列化该集合:

string serialisedReportingData = JsonConvert.SerializeObject( reportingData );
Run Code Online (Sandbox Code Playgroud)

例如,这给了我这个:

[{"Value":11,"Name":"产品编号"},{"Value":false,"Name":"输出 1 已启用"}]

显然,仅凭这些数据,反序列化是不可能的,因为各个集合条目的类型不在 JSON 中。例如,我可以将类型作为 JSON 的一部分,或者提供额外的类型集合以供反序列化期间使用。

我之前使用过 CustomCreationConverter 重载来处理

JsonConvert.DeserializeObject<IEnumerable<Ixxx>>( ... );
Run Code Online (Sandbox Code Playgroud)

类型的场景,但这仅适用于 IEnumerable 内的单个接口类型。在上面的示例中,我有两个:IDerived1 和 IDerived2。

我的疑问/问题:

a) 我不确定如何编写处理多个接口类型的 CustomCreationConverter,并且我不知道如何将类型放入其中。

b)我希望您能提供有关如何实现解决方案的建议,该解决方案将为我提供与我作为输入收到的“IEnumerable reportingData”相同的反序列化输出。

如果可能的话,我非常感谢一个有效的代码示例。

预先非常感谢,克里斯蒂安

Pin*_*ack 5

更新:(受到 dbc 评论的启发)

使用类型名称进行反序列化时,应该使用 SerializationBinder 。请参阅此处了解KnownTypesBinder。(Newtonsoft.Json 需要版本大于 10)

首先,如果你想设置你的属性,你必须创建它们public。然后你可以使用 aJsonSerializerSettings来序列化/反序列化。

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);
Run Code Online (Sandbox Code Playgroud)

如果您使用JsonSerializerSettings类似的方法,类型信息将包含在 json 字符串中。

[{
        "$type": "Base",
        "Name": "Base"
    }, {
        "$type": "Derived1",
        "Value": 3,
        "Name": "Derived1"
    }, {
        "$type": "Derived2",
        "Value": true,
        "Name": "Derived2"
    }
]
Run Code Online (Sandbox Code Playgroud)