繁体   English   中英

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

[英]Serialize multiple objects of different types with JSON

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

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.dll中发生类型'System.Runtime.Serialization.SerializationException'的异常,但未在用户代码中处理

附加信息:不需要使用数据协定名称为“ Class1: http : //schemas.datacontract.org/2004/07/MyProject ”的“ MyProject.Class1”。 将任何静态未知的类型添加到已知类型的列表中-例如,通过使用KnownTypeAttribute属性或将它们添加到传递给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()]。 如果没有,我将收到一个空字符串“ {}”的结果

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

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

我知道了。 唯一要做的就是仅在主基类上添加DataContract属性

[DataContract()]
public class MainBaseClass {}

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

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

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

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

如果要使用DataContractJsonSerializer ,则需要用KnownType属性修饰MainBaseClass ,以便在编译时将所有可能的派生类型通知串行器。 在以下文档中描述了此要求: 数据协定已知类型和此处: 独立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; }
}

这样做之后,一个额外的JSON属性“__type”将发射类型的多态领域MainBaseClass与价值“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序列化

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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