[英]Serialize multiple objects of different types with JSON
I have two classes which inherits from an abstract 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;}
}
Then I created a list of type MainBaseClass in order to serialize both classes in one JSON string but I got this exception 然后,我创建了一个MainBaseClass类型的列表,以便在一个JSON字符串中序列化这两个类,但是出现了此异常
An exception of type 'System.Runtime.Serialization.SerializationException' occurred in System.Runtime.Serialization.dll but was not handled in user code System.Runtime.Serialization.dll中发生类型'System.Runtime.Serialization.SerializationException'的异常,但未在用户代码中处理
Additional information: Type 'MyProject.Class1' with data contract name 'Class1: http://schemas.datacontract.org/2004/07/MyProject ' is not expected. 附加信息:不需要使用数据协定名称为“ Class1: http : //schemas.datacontract.org/2004/07/MyProject ”的“ MyProject.Class1”。 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. 将任何静态未知的类型添加到已知类型的列表中-例如,通过使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型的列表中。
My method does this: 我的方法做到这一点:
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);
My package class 我的包裹类
public class Package<T>
{
public List<T> Objects = new List<T>();
public Package() { }
public void AddObject(T dto)
{
this.Objects.Add(dto);
}
}
My serializer method 我的序列化器方法
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();
}
I also added [DataContract()] on the MainBaseClass and the child classes and the exception persists. 我还在MainBaseClass和子类上添加了[DataContract()],并且异常仍然存在。
It only works if I do this, removing the [DataContract()] from the base class and the child classes previously. 仅当我这样做时才有效,以前从基类和子类中删除了[DataContract()]。 If not, I receive the results as an empty string "{}" 如果没有,我将收到一个空字符串“ {}”的结果
Class1 class1 = getData();
Package<Class1> package = new Package<Class1>();
package.AddObject(class1)
string str = new ServiceClass().Serialize<Package<Class>>(package);
Or this: 或这个:
Class1 class1 = getData();
string str = new ServiceClass().Serialize<Class1>(class1);
So, how can I serialize multiple objects of different types? 那么,如何序列化多个不同类型的对象?
I got it. 我知道了。 The only thing to do is to add DataContract attribute on the main base class only 唯一要做的就是仅在主基类上添加DataContract属性
[DataContract()]
public class MainBaseClass {}
Then, on each child class, we need to add the KnownType attribute 然后,在每个子类上,我们需要添加KnownType属性
[KnownType(typeof(Class1))]
public class Class1 : MainBaseClass
{
}
[KnownType(typeof(Class2))]
public class Class2 : MainBaseClass
{
}
And that's it! 就是这样! That solved my initial problem. 那解决了我最初的问题。
If you are going to use DataContractJsonSerializer
, you need to decorate MainBaseClass
with the KnownType
attribute to inform the serializer of all possible derived types at compile time . 如果要使用DataContractJsonSerializer
,则需要用KnownType
属性修饰MainBaseClass
,以便在编译时将所有可能的派生类型通知串行器。 This requirement is described in the documentation here: Data Contract Known Types and here: Stand-Alone JSON Serialization: Polymorphism 在以下文档中描述了此要求: 数据协定已知类型和此处: 独立JSON序列化:多态
[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; }
}
Having done so, an extra JSON property "__type" will be emitted for polymorphic fields of type MainBaseClass
with value "DataContractName:DataContractNamespace". 这样做之后,一个额外的JSON属性“__type”将发射类型的多态领域MainBaseClass
与价值“DataContractName:DataContractNamespace”。 This syntax is a .Net extension to the JSON standard and gives a hint which concrete type to use later when deserializing. 此语法是JSON标准的.Net扩展,并提示在反序列化时稍后使用哪种具体类型。 Thus if your Package
class looks like: 因此,如果您的Package
类如下所示:
[DataContract]
public class Package<T>
{
[DataMember]
public List<T> Objects = new List<T>();
public Package() { }
public void AddObject(T dto)
{
this.Objects.Add(dto);
}
}
The JSON emitted will look like: 发出的JSON如下所示:
{"Objects":[{"__type":"Class1:#Tile.Question28612192","Id":101,"attrib1":1,"attrib2":2},{"__type":"Class2:#Tile.Question28612192","Id":-101,"attribx":-1,"attriby":-2}]}
If you don't want this, in .Net 4.5 and above, output of type information with DataContractJsonSerializer
can be suppressed by setting DataContractJsonSerializerSettings.EmitTypeInformation
to EmitTypeInformation.Never
: 如果您不希望这样做,在.Net 4.5及更高版本中,可以通过将DataContractJsonSerializerSettings.EmitTypeInformation
设置为EmitTypeInformation.Never
来抑制使用DataContractJsonSerializer
输出类型信息。
var settings = new DataContractJsonSerializerSettings { EmitTypeInformation = EmitTypeInformation.Never };
However, without the type information, you won't be able to deserialize your JSON with DataContractJsonSerializer
later. 但是,如果没有类型信息,以后将无法使用DataContractJsonSerializer
反序列化JSON。
As an alternative, you could consider using Json.NET, which does not require advance knowledge of all possible derived types for serialization. 作为替代方案,您可以考虑使用Json.NET,它不需要对所有可能的派生类型进行序列化的高级知识。 See here: JSON serialization of array with polymorphic objects for details. 有关详细信息,请参见此处: 具有多态对象的数组的JSON序列化 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.