简体   繁体   English

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM