2016-03-10 5 views
3

я получил следующую структуру абстрактных классов:XML класс сериализации с новым свойством, которое скрывает наследуется членом

public abstract class Template 
{ 
    // Some properties and methods defined 
} 

public abstract class Template<TTemplate> : Template where TTemplate : Template 
{ 
// No new properties defined, but methods overriden 
} 

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

public abstract class Model 
{ 
    public Template Template {get;set;} 
    public Model(Template t) {Template = t;} 
    // More properties and methods 
} 

public abstract class Model<TModel, TTemplate> : Model where TModel : Model where TTemplate : Template 
{ 
    public new TTemplate template {get {return (TTemplate)base.Template;} set {base.Template = value;}} 
    public Model(TTemplate t) : base(t) {} 
    // Override some methods but no new properties 
} 

Затем я создаю конкретные классы своего шаблона и моделей и использую их в своем проекте. Эти конкретные классы определяют дополнительные свойства, отличные от тех, которые указаны в абстрактных базовых классах. Моя проблема возникает, когда пришло время сериализовать классы модели. Я использую отражение, чтобы найти все унаследованные типы модели или шаблона и передать их в XmlSerializer, чтобы он мог правильно сериализовать мои абстрактные классы. Тем не менее, я получаю исключение

There was an error reflecting type 'ConcreteModel'. ---> 
System.InvalidOperationException: There was an error reflecting property 
'Template'. ---> System.InvalidOperationException: Member 
ModelOfConcreteModelConcreteTemplate.Template of type ConcreteTemplate hides 
base class member Model.Template of type Template. Use XmlElementAttribute 
or XmlAttributeAttribute to specify a new name. 

я наткнулся на this post on google groups с 2003 года, который имеет целью дать ответ, но я не знаю, как осуществить это исправить (или, если это даже действует 13 лет спустя). Это указывает на то, что сообщение об ошибке вводит в заблуждение, поскольку решение, предложенное в сообщении, не работает.

Если я удаляю «set» accessor из Model.Template и типизированных классов модели (и просто устанавливаю его через конструктор, например), класс сериализуется просто отлично, хотя без свойства Template. Есть ли способ XML-сериализации классов, которые скрывают свойства из (n) (абстрактного) базового класса, без реализации IXmlSerializable на каждом отдельном унаследованном классе?

ответ

3

Я столкнулся с this post от david.woodward, показывая жизнеспособный и по-рельс метод для решения этого сценария (т. Е. При смене базового класса это не вариант). Он предлагает предоставить XmlAttributeOverridesXmlSerializer.

Используя предоставленную объектную модель, следующий код иллюстрирует ее использование. Он работает, явно указывая XmlSerializer на игнорирование скрытого свойства в базовом классе, в данном случае Model.Template.

using System; 
using System.IO; 
using System.Text; 
using System.Xml.Serialization; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     ConcreteTemplate ct = new ConcreteTemplate() { SomeProperty = "hello" }; 
     ConcreteGenericModel cgm = new ConcreteGenericModel(ct); 

     XmlAttributeOverrides attrOverides = new XmlAttributeOverrides(); 
     XmlAttributes attrs = new XmlAttributes() { XmlIgnore = true }; 
     attrOverides.Add(typeof(Model), "Template", attrs); 

     Type[] extraTypes = new Type[0]; 
     XmlSerializer serializer = new XmlSerializer(typeof(ConcreteGenericModel), attrOverides, extraTypes, null, null); 

     StringBuilder sb = new StringBuilder(); 
     using (StringWriter writer = new StringWriter(sb)) 
      serializer.Serialize(writer, cgm); 
     string serializedClass = sb.ToString(); 

     Console.WriteLine(serializedClass); 

     ConcreteGenericModel deserializedCgm; 
     using (StringReader reader = new StringReader(serializedClass)) 
      deserializedCgm = (ConcreteGenericModel)serializer.Deserialize(reader); 

     Console.ReadLine(); 
    } 
} 

public abstract class Template 
{ 
    // Some properties and methods defined 
    public virtual string SomeProperty { get; set; } 
} 

public abstract class Template<TTemplate> : Template where TTemplate : Template 
{ 
    // No new properties defined, but methods overriden 
} 

public class ConcreteTemplate : Template { } 

public abstract class Model 
{ 
    public Model() { } 
    public Template Template { get; set; } 
    public Model(Template t) { Template = t; } 
    // More properties and methods 
} 

public class ConcreteModel : Model 
{ 
    public ConcreteModel(Template t) : base(t) { } 
} 

public abstract class Model<TModel, TTemplate> : Model 
    where TModel : Model 
    where TTemplate : Template 
{ 
    public Model() { } 
    public new TTemplate Template { get { return (TTemplate)base.Template; } set { base.Template = value; } } 
    public Model(TTemplate t) : base(t) { } 
    // Override some methods but no new properties 
} 

public class ConcreteGenericModel : Model<ConcreteModel, ConcreteTemplate> 
{ 
    public ConcreteGenericModel() { } 
    public ConcreteGenericModel(ConcreteTemplate t) : base(t) { } 
} 
+0

Спасибо! Похоже, что это сработает, хотя я обычно передаю 'extraTypes' конструктору' XmlSerializer', что означает, что мне также нужно пространство имен XmlRoot и по умолчанию. Все сериализуется ОК, просто возникает проблема десериализации ... – mmathis

+1

Вы можете передать null для параметров 'root' и' defaultNamespace', которые вам не нужны. Это то, что перегружает другой конструктор, внутренне. Я обновил этот пример, чтобы показать, используя эту перегрузку. – cokeman19

+0

Извините, что столкнулся с старым вопросом, но что произойдет, если мне понадобится как родительский, так и дочерний класс для сериализации? – tyteen4a03