2015-02-19 3 views
0

У меня есть два класса, которые наследуются от абстрактного классасериализация несколько объектов различных типов с 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.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(); 
    } 

Я также добавил [DataContract()] на MainBaseClass и дочерние классы и исключение сохраняются.

Он работает, только если я это сделаю, удалив [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); 

Итак, как я могу сериализировать несколько объектов разных типов?

+0

Вы попробовали [Json.NET] (http://www.newtonsoft.com/json)? – Mehraban

+0

Итак, если я понимаю, это было бы ограничением .net framework? Почему он вообще не работает? Тем временем я рассмотрю ваше предложение. Благодарю. –

ответ

2

У меня есть. Единственное, что нужно сделать, это добавить атрибут DataContract на главном базовом классе только

[DataContract()] 
public class MainBaseClass {} 

Затем на каждом дочернем классе, нам нужно добавить атрибут KnownType

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

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

И это все! Это решило мою первоначальную проблему.

1

Если вы собираетесь использовать DataContractJsonSerializer, вам нужно украсить MainBaseClass с атрибутом KnownType информировать сериалайзер всех возможных производных типов во время компиляции. Это требование описано в документации здесь: 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; } 
} 

Сделав это, дополнительный JSON свойство «__type» будут выделяться для полиморфных полей типа MainBaseClass со значением «DataContractName: DataContractNamespace». Этот синтаксис является.Чистое расширение стандарта JSON и дает подсказку, какой конкретный тип использовать позже при десериализации. Таким образом, если ваш 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 и выше, вывод информации о типе с DataContractJsonSerializer может быть подавлено установкой DataContractJsonSerializerSettings.EmitTypeInformation в EmitTypeInformation.Never:

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

Однако без информации о типе, вы не сможете deserial Добавьте свой JSON с DataContractJsonSerializer.

В качестве альтернативы вы можете рассмотреть возможность использования Json.NET, которая не требует предварительного знания всех возможных производных типов для сериализации. См. Здесь: JSON serialization of array with polymorphic objects.

Смежные вопросы