使用 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 了解详细信息。
我有两个 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 了解详细信息。