Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cascading the effect of an attribute to overridden properties in child classes

Tags:

c#

.net

Is it possible to mark a property in base class with some attribute that remains effective in child classes too?

Question might be very specific to Serialization, but I definitely think there can be other uses as well.

Consider the following code:

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);
            }
        }
    }
}

Above code returns:

------ 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

I thought IsValid_C1 will be ignored, though it is not so. Is there any way of achieving this other than marking the property as protected?

Edit: A quick code to show that XmlIgnore attibute is being inherited. http://ideone.com/HH41TE

like image 732
Abhinav Avatar asked May 07 '13 18:05

Abhinav


People also ask

What is overriding and inheritance?

Overriding and Inheritance : Part of the key to successfully applying polymorphism is understanding that the superclasses and subclasses form a hierarchy which moves from lesser to greater specialization. Used correctly, the superclass provides all elements that a subclass can use directly.

How to call parent class from sub class in Override method?

Invoking overridden method from sub-class : We can call parent class method in overriding method using super keyword . Overriding and constructor : We can not override constructor as parent and child class can never have constructor with same name (Constructor name must always be same as Class name).

What does it mean when attribute is inherited by another class?

3 Answers 3. When Inherited = true (which is the default) it means that the attribute you are creating can be inherited by sub-classes of the class decorated by the attribute. Then use the Attribute by decorating a super-class...

What happens if subclass overridden method throws an exception?

Rule#2 : If the super-class overridden method does throws an exception, subclass overriding method can only throw same, subclass exception. Throwing parent exception in Exception hierarchy will lead to compile time error.Also there is no issue if subclass overridden method is not throwing any exception.


2 Answers

I don't believe there is a way to inherit the attribute since you override the base class property. You would need to decorate the IsValid_C1 of C2 with 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;
        }
    }
like image 184
Bernhard Hofmann Avatar answered Oct 08 '22 04:10

Bernhard Hofmann


I will offer a different view of this question. Maybe you just used those properties as an example and want to have severall properties to be cascaded. But i think that this may be a good time to think about the inheritance model proposed.

Basicly you can use regular inheritance or think about some Design Pattern, that can not just solve you issue related to the serialization, but may offer you some more "loose coupling" in you application, making it in a more component model and allowwing each class to deal only with what is concern, this way you can re-use lots of stuff and make your life easier.

Based on that thinking im providing you a sample of the Decorator Design Pattern mixed with the Strategy Design Pattern. If i were developing classes like the ones on your sample, this is how i would do it:

    /// <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;
            }
        }
    }

Then you need to implement some classes that have the logic of the strategy Pattern, like this:

    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; }
    }

Now that we have the logic separated from the class, we can inherit from the decorators, choosing wich strategy they use to the IsValid field, like this:

    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; }
    }

This is the code to show that the solution works:

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();
    }

The result is:

{<?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>}

So, maybe this does not answer how to cascade the Attribute in this case (because you can easily do it by creating your own attribute(marking to allow inheritance) and then implementing some code to SerializeXML). This is just another option that can improve overall architecture of solutions using Design Pattern. But this solve this particular issue also :)

like image 20
Gabriel Vonlanten C. Lopes Avatar answered Oct 08 '22 02:10

Gabriel Vonlanten C. Lopes