簡體   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