Attribute Inheritance Quirks

Published 04 August 07 08:36 AM | adrian

I was playing with class inheritance AND attributes today, and found out quite a shocking truth (or maybe shocking design, whichever worse).

The truth is: member attributes are always inherited, whether you set the Inherited property in the AttributeUsageAttribute to true or false. This, of course, have some implication that needs to be resolved.

For your better understanding, please review the code below:

  [AttributeUsage(AttributeTargets.All, Inherited = false)]
  public class TestAttribute : Attribute
  {
    private string name;
    public string Name
    {
      get { return name; }
      set { name = value; }
    }
  }

That is the code for the Attribute we're testing (TestAttribute). I've designed it to be attachable to anything (class, method, property, etc.) and not inheritable.

This attribute is set on the class code like the following:

  [Test(Name = "Class Declaration")]
  public class BaseClass
  {
    [Test(Name = "Field Declaration")]
    public int id;
    [Test(Name = "Property Declaration")]
    public int Id
    {
      get { return id; }
      set { id = value; }
    }
    [Test(Name = "Method Declaration")]
    public void Function() { }
  }

I've put an attribute into the class and members. To test the inheritance, I've created a subclass that has nothing:

  public class ChildClass : BaseClass { }

Through Reflection, I've been able to retrieve all members and attributes in the ChildClass.

    private static void Main(string[] args)
    {
      Type type = typeof(ChildClass);

      foreach (TestAttribute attribute in type.GetCustomAttributes(false))
        Console.WriteLine(attribute.Name);
      
      MemberInfo[] minfos = type.GetMembers();
      foreach (MemberInfo info in minfos)
      {
        object[] attributes = info.GetCustomAttributes(false);
        foreach (TestAttribute attribute in attributes)
          Console.WriteLine(attribute.Name);
      }

      Console.ReadLine();
    }

And here's the result:

08_04_2007 08_12

For those who are clueless, this means that you can still access the attributes on the derived class even though you have specifically set the Inherited positional parameter on the attribute to false. The only way to unset this inheritance is to declare an overriding member on the ChildClass.

But then, what if I wanted to override member AND still get an inheritable attribute. Should setting "Inherited = true" does the job? Well, apparently not.

  public class ChildClass : BaseClass
  {
    public override void Function()
    {
    }
  }

I've modified the ChildClass to override one of the members of the BaseClass, changed the Inherited parameter on the attribute, and voila, here's what happens:

08_04_2007 08_21

Boom! This means that the attribute is NOT inherited through overriding. So my current conclusion is the Inherited positional parameters does not work as expected OR there is something wrong with my attribute-getter code (through Reflection).

Anyone has an experience with this?

The end solution I would like to achieve is attribute compartmenting, where attributes from a class does not get propagated to its subclasses with as little code as possible (currently it's already possible, but requires shadowing inherited members with private visibility).

Share this post: | | | |

Comments

# asuhanto said on August 6, 2007 08:18 AM:

I think in relation with OO theory, and not related with the problem you posted, there is no concept like attribute. It is side effect of compiler ability called reflexion. The attribute is there as long as reflexion technology allows.

Put me on the right path if I'm wrong...