2010-07-24 2 views
12

Привет Я пытаюсь сериализовать массив объектов, которые производны от класса, и я продолжаю использовать ту же ошибку, используя C#. Буду признателен за любую оказанную помощь.C# XML-сериализация производных классов

Очевидно, этот пример был уменьшен для цели этого поста в реальном мире. Форма содержала бы множество различных фигур.

Program.cs

namespace XMLInheritTests 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Shape[] a = new Shape[1] { new Square(1) }; 

      FileStream fS = new FileStream("C:\\shape.xml", 
             FileMode.OpenOrCreate); 
      XmlSerializer xS = new XmlSerializer(a.GetType()); 
      Console.WriteLine("writing"); 
      try 
      { 
       xS.Serialize(fS, a); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.InnerException.ToString()); 
       Console.ReadKey(); 
      } 
      fS.Close(); 
      Console.WriteLine("Fin"); 
     } 
    } 
} 

Shape.cs

namespace XMLInheritTests 
{ 
    public abstract class Shape 
    { 
     public Shape() { } 
     public int area; 
     public int edges; 
    } 
} 

Square.cs

namespace XMLInheritTests 
{ 
    public class Square : Shape 
    { 
     public int iSize; 
     public Square() { } 

     public Square(int size) 
     { 
      iSize = size; 
      edges = 4; 
      area = size * size; 
     } 
    } 
} 

Ошибка: System.InvalidOperationException: Тип XMLInheritTests.Square не ожидается. Используйте атрибут XmlInclude или SoapInclude, чтобы указать типы, которые не известны статически.

в Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterShapeA rray.Write2_Shape (String п, Струнный нс, форма о, Boolean IsNullable, Boolean нужно Типа)

в Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterShapeA rray.Write3_ArrayOfShape (Object о)

Большое спасибо

+2

В качестве побочного не публичные поля * обычно * следует избегать; предпочтительнее использовать 'public int Size {get; set;}'. –

+0

Вы можете * также * иметь края и размер как виртуальные свойства 'get', так что вам не нужно ** хранить ** их. –

ответ

19
[XmlInclude(typeof(Square))] 
public abstract class Shape {...} 

(повторить для всех известных подтипов)

Если типы известны только во время выполнения, вы можете предоставить их в конструктор XmlSerializer, но: тогда важно для кэширования и повторного использования экземпляра serializer; иначе вы будете геморрагировать динамически созданные сборки. Он делает это автоматически, когда вы используете конструктор, который принимает только Type, но не для других перегрузок.

+0

Прохладный Я думаю, что у меня все работает (на данный момент: S), большое спасибо – 111111

+0

Удивительно, теперь как бы это сделать для нескольких унаследованных классов. (Пример сохранения темы фигур) Shape-> Square-> ColoredSquare? –

+0

Вы писали: 'но: ** тогда ** важно кэшировать и повторно использовать этот экземпляр serializer ...' (мой акцент). Ваши рассуждения зависят от конструктора, а не от 'Type', поставляемого динамически. Или я что-то пропустил? – ispiro

3

Решение:

class Program 
    { 
     static void Main(string[] args) 
     { 
      Shape[] a = new Shape[2] { new Square(1), new Triangle() }; 

      FileStream fS = new FileStream("C:\\shape.xml",FileMode.OpenOrCreate); 

      //this could be much cleaner 
      Type[] t = { a[1].GetType(), a[0].GetType() }; 


      XmlSerializer xS = new XmlSerializer(a.GetType(),t); 
      Console.WriteLine("writing"); 
      try 
      { 
       xS.Serialize(fS, a); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.InnerException.ToString()); 
       Console.ReadKey(); 
      } 
      fS.Close(); 
      Console.WriteLine("Fin"); 
     } 
    } 

namespace XMLInheritTests 
{ 
    [XmlInclude(typeof(Square))] 
    [XmlInclude(typeof(Triangle))] 
    public abstract class Shape 
    { 
     public Shape() { } 
     public int area; 
     public int edges; 
    } 
} 

Спасибо; У меня, несомненно, будет еще одна проблема очень скоро: S

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