【问题标题】:Serialize multiple objects of different types with JSON使用 JSON 序列化多个不同类型的对象
【发布时间】:2015-02-19 16:54:22
【问题描述】:

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

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” 名称 'Class1:http://schemas.datacontract.org/2004/07/MyProject' 不是 预期的。将任何静态未知的类型添加到已知列表中 类型 - 例如,通过使用 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);

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

【问题讨论】:

  • 你试过Json.NET吗?
  • 那么,如果我理解的话,这将是 .net 框架的限制?为什么它根本不起作用?同时我会审查你的建议。谢谢。

标签: c# json serialization types


【解决方案1】:

如果要使用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 且值为“DataContractName:DataContractNamespace”的多态字段发出一个额外的 JSON 属性“__type”。此语法是对 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

【讨论】:

    【解决方案2】:

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

    [DataContract()]
    public class MainBaseClass {}
    

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-28
      • 2012-06-04
      • 2015-02-22
      • 1970-01-01
      • 2020-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多