DataContractSerializer требует конструктор без параметров в абстрактном базовом классе - PullRequest
4 голосов
/ 10 июня 2011

Когда у меня есть следующие классы, и я пытаюсь сериализовать экземпляр ConcreteClass с DataContractSerializer .WriteObject(..), я получаю InvalidDataContractException.

public abstract class AbstractClass
{            
  protected AbstractClass(string text) { }
}

public class ConcreteClass : AbstractClass
{
  public ConcreteClass() : base("text") {  } 
}

Создан экземпляр сериализаторас new DataContractSerializer(typeof(ConcreteClass).

Использование XmlSerializer не создает проблем.

Теперь при добавлении public AbstractClass() {}

оба сериализатора работают.

* 1020Так почему же DataContractSerializer требует, чтобы абстрактные базовые классы имели конструктор без параметров? Здесь указано, что могут быть сериализованы типы, которые "имеют конструктор без параметров", что верно для ConcreteClass.Я также добавил некоторый код в этот требуемый конструктор, и я не думаю, что он когда-либо вызывался во время процесса сериализации.

Полное исключение гласит:

System.Runtime.Serialization.InvalidDataContractException: Тип AbstractClass 'не может быть сериализован.Попробуйте пометить его атрибутом DataContractAttribute и пометить все его элементы, которые вы хотите сериализовать, атрибутом DataMemberAttribute.См. Документацию по Microsoft .NET Framework для других поддерживаемых типов.

Это работает даже если я оставляю конструктор без параметров и вместо этого использую предложенный атрибут.Так почему же есть разница и почему делается попытка сериализации абстрактного класса?Конечно, в абстрактном классе могут быть такие вещи, как свойства, но не следует ли их сериализовать вместе с экземпляром ConcreteClass (который наследует такие вещи)?

Edit :

Мой точный код:

namespace SerilizationTest
{
  public abstract class AbstractClass
  {
    public string StringProperty { get; set; }

    //This constructor is required (although never called).
    //If not present we get "InvalidDataContractException :
    //Type AbstractClass cannot be serialized"
    public AbstractClass()
    {
      Console.WriteLine("We won't see this.");
    }

    public AbstractClass(string text)
    {
      StringProperty = text;
    }
  }

  public class ConcreteClass : AbstractClass
  {
    public ConcreteClass() : base("text") { }
  }

  class Program
  {
    static void Main()
    {
      var serializer = new DataContractSerializer(typeof(ConcreteClass));
      var memStream = new MemoryStream();
      serializer.WriteObject(memStream, new ConcreteClass());
      memStream.Seek(0, SeekOrigin.Begin);
      var deserializedObj = (ConcreteClass)serializer.ReadObject(memStream);
      Console.WriteLine(deserializedObj.StringProperty);
    }
  }
}

1 Ответ

0 голосов
/ 24 июля 2012

Исключение, которое вы получаете, говорит о том, что в AbstractClass отсутствует атрибут [DataContract].

DataContract - это атрибут, который используется для маркировки классов, которые могут быть сериализуемыми. Этот атрибут будет включать в ваш класс только те атрибуты, которые нужно сериализовать, если вы скажете это сделать с помощью атрибута DataMember.

Атрибут DataMember используется, чтобы отметить, какие атрибуты вы хотите в вашем сериализуемом классе.

Этот атрибут находится в System.Runtime.Serialization;

Например ...

public abstract class Bar
{
}

public class Foo : Bar
{
    string one { get; set; }
    string two { get; set; }
    string three { get; set; }
}

Если я попытаюсь сериализовать свой класс Foo, я получу ваше исключение. Поэтому, если я добавлю атрибут DataContract в свой класс Bar, как предполагает исключение, в следующий раз, когда я попытаюсь сериализоваться, я получу ту же ошибку, просто указывающую на другую часть моего кода, сам класс Foo. Что мне нужно сделать, это добавить DataContract для обоих, как это.

[DataContract]
public abstract class Bar
{
}

[DataContract]
public class Foo : Bar
{
    string one { get; set; }
    string two { get; set; }
    string three { get; set; }
}

Так что теперь у нас будет возможность создать сериализованный файл. Однако никакой информации не будет, поскольку мы никогда не указывали нашему DataContract, что включать. Чтобы решить эту проблему, мы добавляем атрибут DataMember к атрибутам в классе, который мы хотим включить.

[DataContract]
public class Foo : Bar
{
    [DataMember]
    string one { get; set; }
    string two { get; set; }
    [DataMember]
    string three { get; set; }
}

Если атрибуты DataMember добавлены при сериализации этого класса, он будет сериализовать только информацию о первой и третьей строке. Вторая строка не будет включена, поскольку она не была специально помечена атрибутом DataMember.

...