使用 JSON 序列化多个不同类型的对象

Serialize multiple objects of different types with JSON

我有两个 class 继承自抽象 class

public class Class1 : MainBaseClass
{
   public int attrib1 {get; set;}
   public int attrib2 {get; set;}
}

public class Class2 : MainBaseClass
{
   public int attribx {get; set;}
   public int attriby {get; set;}
}

然后我创建了一个 MainBaseClass 类型的列表,以便在一个 JSON 字符串中序列化两个 classes 但我得到了这个异常

An exception of type 'System.Runtime.Serialization.SerializationException' occurred in System.Runtime.Serialization.dll but was not handled in user code

Additional information: Type 'MyProject.Class1' with data contract name 'Class1:http://schemas.datacontract.org/2004/07/MyProject' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.

我的方法是这样做的:

Class1 class1 = getData();
Class2 class2 = getData();
Package<MainBaseClass> package = new Package<MainBaseClass>();
package.AddObject(class1)
package.AddObject(class2);
//Here's the error
new ServiceClass().Serialize<Package<MainBaseClass>>(package);

我的包裹class

public class Package<T>
{
    public List<T> Objects = new List<T>();

    public Package() { }

    public void AddObject(T dto)
    {
        this.Objects.Add(dto);
    }
}

我的序列化器方法

    public static string Serialize<T>(T entity)
    {
        MemoryStream stream = new MemoryStream();
        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
        //Here's the exception
        ser.WriteObject(stream, entity);
        stream.Position = 0;
        StreamReader sr = new StreamReader(stream);
        return sr.ReadToEnd();
    }

我还在 MainBaseClass 和子 classes 上添加了 [DataContract()],异常仍然存在。

它只有在我这样做时才有效,之前从基 class 和子 classes 中删除 [DataContract()]。如果不是,我收到的结果是一个空字符串“{}”

Class1 class1 = getData();
Package<Class1> package = new Package<Class1>();
package.AddObject(class1)
string str = new ServiceClass().Serialize<Package<Class>>(package);

或者这样:

Class1 class1 = getData();
string str = new ServiceClass().Serialize<Class1>(class1);

那么,如何序列化多个不同类型的对象?

我明白了。唯一要做的就是在主基class only

上添加DataContract属性
[DataContract()]
public class MainBaseClass {}

然后,在每个 child class 上,我们需要添加 KnownType 属性

[KnownType(typeof(Class1))]
public class Class1 : MainBaseClass
{
}

[KnownType(typeof(Class2))]
public class Class2 : MainBaseClass
{
}

就是这样!这解决了我最初的问题。

如果您要使用 DataContractJsonSerializer, you need to decorate MainBaseClass with the KnownType attribute to inform the serializer of all possible derived types at compile time. This requirement is described in the documentation here: Data Contract Known Types and here: Stand-Alone JSON Serialization: Polymorphism

[DataContract]
[KnownType(typeof(Class1))]
[KnownType(typeof(Class2))]
public abstract class MainBaseClass
{
    [DataMember]
    public int Id { get; set; } // For instance.
}

[DataContract]
public class Class1 : MainBaseClass
{
    [DataMember]
    public int attrib1 { get; set; }
    [DataMember]
    public int attrib2 { get; set; }
}

[DataContract]
public class Class2 : MainBaseClass
{
    [DataMember]
    public int attribx { get; set; }
    [DataMember]
    public int attriby { get; set; }
}

这样做之后,将为 MainBaseClass 类型和值 "DataContractName:DataContractNamespace" 的多态字段发出额外的 JSON 属性“__type”。此语法是 JSON 标准的 .Net 扩展,并给出了稍后在反序列化时使用哪种具体类型的提示。因此,如果您的 Package class 看起来像:

[DataContract]
public class Package<T>
{
    [DataMember]
    public List<T> Objects = new List<T>();

    public Package() { }

    public void AddObject(T dto)
    {
        this.Objects.Add(dto);
    }
}

发出的 JSON 看起来像:

{"Objects":[{"__type":"Class1:#Tile.Question28612192","Id":101,"attrib1":1,"attrib2":2},{"__type":"Class2:#Tile.Question28612192","Id":-101,"attribx":-1,"attriby":-2}]}

如果你不想这样,在 .Net 4.5 及更高版本中,可以通过设置 DataContractJsonSerializerSettings.EmitTypeInformation to EmitTypeInformation.Never:

来抑制带有 DataContractJsonSerializer 的类型信息的输出
var settings = new DataContractJsonSerializerSettings { EmitTypeInformation = EmitTypeInformation.Never };

但是,如果没有类型信息,您以后将无法使用 DataContractJsonSerializer 反序列化您的 JSON。

作为替代方案,您可以考虑使用 Json.NET,它不需要提前了解所有可能的序列化派生类型。请参阅此处:JSON serialization of array with polymorphic objects 了解详细信息。