InvalidOperationException при XML-сериализации наследуемого класса - PullRequest
4 голосов
/ 12 октября 2009

У меня проблема с сериализацией класса c # в файл XML с базовым классом ... вот простой пример:

namespace Domain
{
   [Serializable]
   public class ClassA
   {
      public virtual int MyProperty
      {
         get; set;
      }
   }
}

namespace Derived
{
   public class ClassA : Domain.ClassA
   {
      public override int MyProperty
      {
         get { return 1; } set { /* Do Nothing */ }
      }
   }
}

Когда я пытаюсь сериализовать экземпляр Derived.ClassA, я получаю следующее исключение:

InvalidOperationException (типы 'Domain.ClassA' и 'Derived.ClassA' оба используют имя типа XML 'ClassA' из пространства имен ". Используйте атрибуты XML, чтобы указать уникальное имя XML и / или пространство имен для типа.)

Проблема в том, что я хочу создать один базовый класс, который просто определяет структуру XML-файла, а затем разрешать кому-либо еще наследовать этот класс для вставки бизнес-правил, но форматирование будет проходить из базы .

Возможно ли это, и если да, то как мне приписать базовый класс, чтобы разрешить это?

Ответы [ 6 ]

5 голосов
/ 02 декабря 2009

Это помогло нам.

[XmlType(TypeName = "DerivedClassA")] 
2 голосов
/ 13 октября 2009

Если вы можете переименовать производные классы в нечто отличное от их базового класса, вы можете использовать XmlAttributeOverrides, чтобы сделать это:

// For ClassB, which derives from ClassA
XmlAttributes          attributes  = new XmlAttributes();                        
attributes.XmlRoot                 = new XmlRootAttribute("ClassA");

XmlAttributeOverrides  overrides   = new XmlAttributeOverrides();
overrides.Add(typeof(ClassB), attributes);

XmlSerializer   serializer  = new XmlSerializer(typeof(ClassB), overrides);

Это будет сериализовано в <ClassA> ... </ClassA> и может сериализироваться из этого в ClassB экземпляров.

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

0 голосов
/ 13 марта 2010

Это просто информация, поскольку она не дает конкретного ответа, но вот хорошая статья из выпуска MSDN за июль 2003 года, в которой обсуждаются эти конфликты имен. "Столкновения пространства имен XML, XmlNodeList и десериализация и многое другое" .

0 голосов
/ 04 января 2010

У меня была такая же проблема, но с дополнительным ограничением: нет доступа к источнику ни для класса Domain, ни для производных классов.Производный объект, унаследованный от объекта Domain, и, поскольку у классов были одинаковые неквалифицированные имена, XmlSerializer не смог бы сериализовать объект класса Derived.

Возможно, это можно было решить с помощью грубой силы (изменениеIL для одного из классов, чтобы добавить соответствующие атрибуты), но я хотел что-то "чище".Вот что сработало:

var attrs = new XmlAttributes();
attrs.XmlType = new XmlTypeAttribute("anythingButClassA");

var overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Domain.ClassA), attrs);

var serializer = new XmlSerializer(typeof(Derived.ClassA), overrides);
serializer.Serialize(Console.Out, new Derived.ClassA());

Даже если вы являетесь автором классов Domain и / или Derived, вам не нужно их переименовывать.

0 голосов
/ 13 октября 2009

Установить базовое пространство имен для вашего домена и задать имя настраиваемого элемента для производного класса:

namespace Domain
{
    [Serializable]
    [XmlRoot(Namespace = "http://mynamespace/domain/2009/")]
    public class ClassA
    {
        [XmlIgnore]
        public virtual int MyProperty { get; set; }
    }
}

namespace Derived
{
    [Serializable]
    [XmlRoot(ElementName = "DerivedClassA")]
    public class ClassA : Domain.ClassA
    {
        public override int MyProperty
        {
            get
            {
                return 1;
            }
            set
            {
                base.MyProperty = value;
            }
        }
    }
}
0 голосов
/ 12 октября 2009

Я думаю, что ваш производный класс также должен быть помечен атрибутом [Serializable] для сериализации / десериализации.

Помимо атрибута serializable, вам также нужно сделать так, чтобы у одного из двух было другое имя XML - как говорится в ошибке, в «мире XML» они оба называются «ClassA». Один из них должен быть назван по-другому, используя атрибут XmlElement (при условии, что вы используете XmlSerializer - верно?)

namespace Domain
{
   [Serializable]
   [XmlElement(ElementName="ClassABase")]
   public class ClassA
   {
      public virtual int MyProperty
      {
         get; set;
      }
   }
}

namespace Derived
{
   [Serializable]
   public class ClassA : Domain.ClassA
   {
      public override int MyProperty
      {
         get { return 1; } set { /* Do Nothing */ }
      }
   }
}

Марк

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...