C Sharp

Specifying Inheritance Attribute Rules

The last parameter for the AttributeUsageAttribute attribute is the inherited flag, which dictates whether the attribute can be inherited. The default for this value is false.However, if the inherited flag is set to true, its meaning is dependent on the value of the AllowMultiple flag. If the inherited flag is set to true and the AllowMultiple flag is false, the attribute will override the inherited attribute. However, if the inherited flag is set to true and the AllowMultiple flag is also set to true, the attribute accumulates on the member.

Attribute Identifiers

Look at the following line of code, and try to figure out whether the attribute annotates the return value or the method: -

class MyClass
    public long Foo();

If you have some COM experience, you know that an HRESULT is the standard return type for all methods not named AddRef or Release. However, it's easy to see that if the attribute name could apply to both the return value and the method name, it would be impossible for the compiler to know what your intention is. Here are some other scenarios where the compiler would not know your intention by context: -

  • method vs. return type
  • event vs. field vs. property
  • delegate vs. return type
  • property vs. accessor vs. return value of getter method vs. value parameter of setter method

In each of these cases, the compiler makes a determination based on what's considered "most common." To override this determination, you use an attribute identifier, all of which are listed here: -

  • assembly
  • module
  • type
  • method
  • property
  • event
  • field
  • param
  • return

To use an attribute identifier, preface the attribute name with the identifier and a colon. In the MyClass example, if you wanted to make sure the compiler could determine that the HRESULT attribute is meant to annotate the return value and not the method, you would specify it as follows: -

class MyClass
    public long Foo();


C# attributes provide a mechanism for annotating types and members at design time with information that can later be retrieved at run time through reflection. This gives you the ability to create truly self-contained, self-describing components without having to resort to stuffing necessary bits into resource files and constants. The advantage is a more mobile component that is both easier to write and easier to maintain.