2009-10-12 5 views
4

Я имею вопрос сериализации переменного тока # класс в файл XML, который имеет базовый класс ... вот простой пример:InvalidOperationException Когда 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-файла, а затем разрешает кому-либо из этого класса извлекать из этого класса для вставки бизнес-правил, но форматирование будет проходить из базы.

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

+0

Спасибо за ввод. Проблема в том, что я редко задаю вопросы, и когда я это делаю, они, как правило, очень жесткие, и мне еще предстоит получить ответ на вопрос, который я задал, который помог мне еще. Так что мне делать? – Nick

+0

Это действительно сложная ситуация ... вы * должны * принимать ответы, но если вы не получите никаких полезных ответов, трудно выбрать один, чтобы принять ... У меня нет окончательного ответа на этот вопрос. .. –

+0

Я согласен ... Это не значит, что я не хочу принимать ответы. В то же время я не хочу принимать ответы, просто чтобы сказать, что я их принял. Я думаю, что это побеждает цель и изменяет смысл того, что означает «принятое». – Nick

ответ

2

Если вы свободны переименовать производные классы нечто иное, чем их базовый класс, вы можете использовать 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 случаях.

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

+0

Решение, которое в конечном итоге сработало, было похоже на это, но не так сложно. Вы правы в том, что имена классов .NET должны быть разными ... к сожалению, пространства имен .NET не используются по какой-либо причине. Таким образом, самым простым было иметь ClassABase для простой версии и приложить к нему атрибут XmlRoot класса ClassA, а затем получить производный класс ClassA. Тогда они оба серийно идентичны. Переопределяет как часть сериализатора, где не требуется. – Nick

+0

Отлично! Но это будет работать для ClassB, который происходит от ClassABase? Или вам нужен только один подкласс? –

0

Я думаю, что ваш производный класс также должен быть помечен атрибутом [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 */ } 
     } 
    } 
} 

Марк

+0

Пробовал это, но это не помогло. Что-нибудь еще? – Nick

0

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

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; 
      } 
     } 
    } 
} 
5

Это сделал трюк для нас.

[XmlType(TypeName = "DerivedClassA")] 
0

У меня была эта же проблема, но с дополнительным ограничением: нет доступа к источнику для классов Domain или Derived. Производный объект, унаследованный от объекта 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()); 

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

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