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

时间:2015-02-19 16:54:23

标签: c# json serialization types

我有两个继承自抽象类的类

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字符串中序列化这两个类但是我得到了这个异常

  

类型的例外   ' System.Runtime.Serialization.SerializationException'发生在   System.Runtime.Serialization.dll但未在用户代码中处理

     

其他信息:键入' MyProject.Class1'与数据合同   名称'第1类:http://schemas.datacontract.org/2004/07/MyProject'不是   预期。将任何静态未知的类型添加到已知列表中   types - 例如,通过使用KnownTypeAttribute属性或by   将它们添加到传递给的已知类型列表中   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);

我的包类

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上添加了[DataContract()],子类和异常仍然存在。

只有在我这样做的情况下才能工作,之前从基类和子类中删除[DataContract()]。如果没有,我会将结果作为空字符串&#34; {}&#34;

收到
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);

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

2 个答案:

答案 0 :(得分:2)

我明白了。唯一要做的就是只在主基类上添加DataContract属性

[DataContract()]
public class MainBaseClass {}

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

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

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

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

答案 1 :(得分:2)

如果您要使用DataContractJsonSerializer,则需要使用KnownType属性修饰MainBaseClass,以便在编译时通知序列化程序所有可能的派生类型 。此处的文档中描述了此要求:Data Contract Known Types和此处: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的多态字段发出额外的JSON属性“__type”,其值为“DataContractName:DataContractNamespace”。此语法是JSON标准的.Net扩展,并提供了一个提示,以便在反序列化时使用哪种具体类型。因此,如果您的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);
    }
}

发出的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设置为EmitTypeInformation.Never来抑制DataContractJsonSerializer类型信息的输出:

var settings = new DataContractJsonSerializerSettings { EmitTypeInformation = EmitTypeInformation.Never };

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

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