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

私はこの質問について別の見方をします。これらのプロパティを例として使用しただけで、複数のプロパティをカスケードしたいと思うかもしれません。しかし、これは、提案された継承モデルについて考える良い機会かもしれないと思います。

基本的に、通常の継承を使用するか、シリアライゼーションに関連する問題を解決するだけでなく、アプリケーションで「疎結合」を提供して、より多くのコンポーネントモデルにし、各クラスを許可するいくつかのデザインパターンについて考えることができます関心のあるものだけに対処することで、多くのものを再利用して生活を楽にすることができます。

その考えに基づいて、Decorator デザイン パターンと Strategy デザイン パターンを組み合わせたサンプルを提供します。あなたのサンプルのようなクラスを開発していた場合、これは私がそれを行う方法です:

    /// <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 にコードを実装することで簡単に実行できるため)。これは、デザイン パターンを使用してソリューションの全体的なアーキテクチャを改善できるもう 1 つのオプションです。しかし、これはこの特定の問題も解決します:)

于 2013-05-17T17:55:19.463 に答える
1

基本クラスのプロパティをオーバーライドするため、属性を継承する方法があるとは思いません。C2 の IsValid_C1 を XmlIgnore で装飾する必要があります。

    [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

必要な動作は、クラス 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 に答える