11

是否可以使用在子类中仍然有效的某些属性来标记基类中的属性?

问题可能非常特定于序列化,但我绝对认为也可以有其他用途。

考虑以下代码:

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

4 回答 4

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;
        }
    }
于 2013-05-08T07:37:41.840 回答
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 来轻松地做到这一点)。这只是可以使用设计模式改进解决方案整体架构的另一种选择。但这也解决了这个特殊问题:)

于 2013-05-17T17:55:19.463 回答
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);
    }

Main 方法变为:

    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);
        }
    }
于 2015-01-27T06:14:09.010 回答
0

看来此功能在 C# 中已损坏。

您可以编写一个属性,通过反射将为您降低属性。如果您了解反射,那就很简单了。

于 2015-05-06T00:43:46.107 回答