【问题标题】:XML serialize class with new property which hides inherited member具有隐藏继承成员的新属性的 XML 序列化类
【发布时间】:2016-03-10 23:52:20
【问题描述】:

我有以下抽象类的结构:

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:反映属性时出现错误 '模板'。 ---> System.InvalidOperationException:成员 ModelOfConcreteModelConcreteTemplate.ConcreteTemplate 类型的模板隐藏 基类成员 Model.Template 类型的模板。使用 XmlElementAttribute 或 XmlAttributeAttribute 指定新名称。

我在 2003 年遇到了 this post on google groups,它声称可以给出答案,但我不确定如何实施该修复(或者它是否在 13 年后仍然有效)。它确实表明该错误消息具有误导性,因为该消息提出的解决方案不起作用。

如果我从 Model.Template 和类型化的 Model 类中删除“set”访问器(例如,只需通过构造函数设置它),该类就可以很好地序列化 - 尽管没有 Template 属性。有没有一种方法可以对隐藏 a(n)(抽象)基类的属性的类进行 XML 序列化,而无需在每个继承的类上实现 IXmlSerializable?

【问题讨论】:

    标签: c# xml inheritance


    【解决方案1】:

    我遇到了 david.woodward 的 this post,它展示了一种可行的即时方法来处理这种情况(即,当不能更改基类时)。它建议将XmlAttributeOverrides 提供给XmlSerializer

    使用您提供的对象模型,以下代码说明了它的用法。它通过明确告诉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) { }
    }
    

    【讨论】:

    • 谢谢!看起来这会起作用,尽管我通常将extraTypes 传递给XmlSerializer 构造函数,这意味着我还需要一个XmlRoot 和默认命名空间。一切都可以序列化,只是现在反序列化有问题......
    • 您可以为不需要的rootdefaultNamespace 参数传递null。这是其他构造函数重载在内部所做的。我已更新示例以显示使用此重载。
    • 很抱歉碰到一个老问题,但是如果我需要父类和子类都序列化会发生什么?
    • 序列化可能必须为父类和子类分别显式控制/配置。如果你有一个具体的例子,你能否创建一个新问题,参考这个问题(如果相关)?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 2010-09-05
    • 2011-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多