将属性的效果级联到子类中的重写属性

时间:2013-05-07 18:56:39

标签: c# .net

是否可以在基类中标记一个属性,该属性在子类中仍然有效?

问题可能对序列化非常具体,但我绝对认为还可以有其他用途。

请考虑以下代码:

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

namespace Code.Without.IDE
{
    [Serializable]
    public abstract class C1
    {
        [XmlIgnore]
        public abstract bool IsValid_C1 { get; set;}
    }

    [Serializable]
    public class C2 : C1
    {
        public bool IsValid_C2 { get; set; }

        public override bool IsValid_C1 { get; set;}

        public C2()
        {
            IsValid_C1 = true;
            IsValid_C2 = false;
        }
    }

    public static class AbstractPropertiesAttributeTest
    {
        public static void Main(string[] args)
        {
            C2 c2 = new C2();
            using(MemoryStream ms = new MemoryStream())
            {
                XmlSerializer ser = new XmlSerializer(typeof(C2));
                ser.Serialize(ms, c2);
                string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
                Console.WriteLine(result);
            }
        }
    }
}

以上代码返回:

------ C:\abhi\Code\CSharp\without IDE\AbstractPropertiesAttributeTest.exe 
<?xml version="1.0"?>
<C2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <IsValid_C2>false</IsValid_C2>
  <IsValid_C1>true</IsValid_C1>
</C2>
------ Process returned 0

我认为IsValid_C1会被忽略,但事实并非如此。除了将财产标记为受保护之外,有没有办法实现这一目标?

编辑:一个快速代码,用于显示正在继承XmlIgnore属性。 http://ideone.com/HH41TE

4 个答案:

答案 0 :(得分:1)

我不相信有一种方法可以继承该属性,因为您覆盖了基类属性。你需要用XmlIgnore来装饰C2的IsValid_C1:

    [Serializable]
    public class C2 : C1
    {
        public bool IsValid_C2 { get; set; }

        [XmlIgnore]
        public override bool IsValid_C1 { get; set; }

        public C2()
        {
            IsValid_C1 = true;
            IsValid_C2 = false;
        }
    }

答案 1 :(得分:1)

我将对这个问题提出不同的看法。也许你只是使用这些属性作为一个例子,并希望有几个属性可以级联。但我认为这可能是思考提出的继承模型的好时机。

基本上你可以使用常规继承或者考虑一些设计模式,这不仅可以解决与序列化相关的问题,而且可以在你的应用程序中为你提供更多的“松散耦合”,使其成为更多的组件模型和允许每个班级只处理所关注的问题,这样你就可以重复使用大量的东西,让你的生活更轻松。

基于这种想法,我将为您提供与策略设计模式混合的装饰器设计模式的示例。如果我正在开发类似你样本中的类,那么我就是这样做的:

    /// <summary>
    /// The interface for validation strategy (since we are using interface, there is no need for another abstract class)
    /// </summary>
    public interface IValidation
    {
        bool IsValid { get; set; }
    }

    /// <summary>
    /// The decorator (it dont need to be abstract) that has the serializable properties
    /// </summary>
    [Serializable]
    public class ValidatableDecorator : IValidation
    {
        protected IValidation instance;

        public ValidatableDecorator()
        {
            Init();
        }
        public ValidatableDecorator(IValidation instance)
        {
            Init();
        }

        protected virtual void Init() { }

        public void Set(IValidation instance)
        {
            this.instance = instance;
        }

        [XmlIgnore]
        public bool IsValid
        {
            get
            {
                return instance.IsValid;
            }
            set
            {
                instance.IsValid = value;
            }
        }
    }

然后你需要实现一些具有策略模式逻辑的类,如下所示:

    public class BossValidatorImplementation : IValidation
    {

        public bool IsValid
        {
            get
            {
                return false; ;
            }
            set
            {
                throw new InvalidOperationException("I dont allow you to tell me this!");
            }
        }
    }

    public class EasyGoingValidator : IValidation
    {
        public bool IsValid { get; set; }
    }

现在我们已经将逻辑与类分开了,我们可以继承装饰器,选择他们用于IsValid字段的策略,如下所示:

    public class ChildWithBossValidation : ValidatableDecorator
    {
        protected ChildWithBossValidation(IValidation instance)
            : this()
        {
            Init();
        }

        public ChildWithBossValidation()
            : base(new BossValidatorImplementation())
        {
            Init();
        }

        protected override void Init()
        {
            Name = "I'm the boss!";
            Sallary = 10000d;
        }

        public string Name { get; set; }
        public double Sallary { get; set; }

    }

    public class ChildWithEasyGoingValidation : ValidatableDecorator
    {
        public ChildWithEasyGoingValidation()
            : base(new EasyGoingValidator())
        {
        }
        protected ChildWithEasyGoingValidation(IValidation instance)
            : this()
        {
        }

        protected override void Init()
        {
            Name = "Do as you please... :)  ";
        }

        public string Name { get; set; }
    }

这是显示解决方案有效的代码:

public static void Main(string[] args)
    {

        var boos = new ChildWithBossValidation();
        var coolGuy = new ChildWithEasyGoingValidation();

        using (var ms = new MemoryStream())
        {
            var ser = new XmlSerializer(boos.GetType());
            ser.Serialize(ms, boos);
            string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
            Console.WriteLine("With override");
            Console.WriteLine(result);
        }

        Console.WriteLine("-------------");

        using (var ms = new MemoryStream())
        {
            var ser = new XmlSerializer(coolGuy.GetType());
            ser.Serialize(ms, coolGuy);
            string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
            Console.WriteLine("With override");
            Console.WriteLine(result);
        }

        Console.ReadKey();
    }

结果是:

{<?xml version="1.0"?>
<ChildWithBossValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>I'm the boss!</Name>
  <Sallary>10000</Sallary>
</ChildWithBossValidation>-------------------<?xml version="1.0"?>
<ChildWithEasyGoingValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Do as you please... :)  </Name>
</ChildWithEasyGoingValidation>}

所以,在这种情况下,也许这并没有回答如何级联属性(因为您可以通过创建自己的属性(标记为允许继承)然后将一些代码实现到SerializeXML来轻松实现)。这只是另一种可以使用Design Pattern改进解决方案整体架构的选项。但这也解决了这个特殊问题:)

答案 2 :(得分:1)

使用类XmlAttributeOverrides和XmlAttributes可以实现所需的行为。我已经为XmlSerializer创建了帮助方法:

    public static XmlSerializer GetXmlSerializerWithXmlIgnoreFields(Type t)
    {
        XmlAttributeOverrides xmlOverrides = new XmlAttributeOverrides();

        foreach (var prop in t.GetProperties(BindingFlags.Public|BindingFlags.Instance))
        {
            Attribute xmlIgnoreAttribute = Attribute.GetCustomAttribute(prop, typeof(XmlIgnoreAttribute));
            if (xmlIgnoreAttribute == null) 
                continue;

            XmlAttributes xmlAttributes = new XmlAttributes();
            xmlAttributes.XmlIgnore = true;
            xmlOverrides.Add(t, prop.Name, xmlAttributes);
        }

        return new XmlSerializer(t, xmlOverrides);
    }

主要方法成为:

    public static void Main(string[] args)
    {
        C2 c2 = new C2();
        using (MemoryStream ms = new MemoryStream())
        {
            XmlSerializer ser = GetXmlSerializerWithXmlIgnoreFields(typeof(C2));
            ser.Serialize(ms, c2);
            string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
            Console.WriteLine(result);
        }
    }

答案 3 :(得分:0)

看来这个功能在C#中被破坏了。

您可以编写一个属性,通过反射将为您降低属性。如果你理解反思,那就非常直截了当。