#473 – Specifying what Type of Elements a Custom Attribute Can Be Applied To

When you define a custom attribute, you can attach it to a variety of program elements by default.  But if your attribute is meant to apply to only one (or more) elements, you can specify that when you define the attribute.

You define which elements your custom attributes can be attached to by specifying the AttributeUsage attribute along with the definition of your attribute.  You specify one or more AttributeTargets values.  (Intellisense will provide a list, as shown below).

In the example below, I’ve specified that the PopCulture attribute may be used on parameters, properties and fields.

    [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field)]
    public sealed class PopCultureAttribute : Attribute
    {

If we try attaching the attribute to an unsupported element, like a method, we get an error at compile time.

#472 – Attributes Can Be Attached to a Variety of Elements

Custom attributes can be attached not only to class methods, but to a number of different types of elements.

You can attach an attribute to any of the following elements:

  • An assembly
  • A class
  • A constructor
  • A delegate
  • An enumerated type
  • An event
  • A field
  • A generic parameter
  • An interface
  • A method
  • A module (.dll or .exe)
  • A parameter
  • A property
  • A return value
  • A struct

Below is an example of attaching custom attributes to parameters.

    public sealed class PopCultureAttribute : Attribute
    {
        public string Trivia;
        public object SuggestedValue;

        public PopCultureAttribute(string trivia, object suggestedValue)
        {
            Trivia = trivia;
            SuggestedValue = suggestedValue;
        }
    }

 

        public void FeedCowInBarn(
            [PopCulture("Cows stomachs can bloat when feeding them rich grains", "Silage")] string feedType,
            [PopCulture("Cows spend 6 hrs/day eating", 60)] int numMinutes)
        {
            Console.WriteLine("Cow eats slop in dim confines of barn.  {0}, {1}", feedType, numMinutes);
        }

#470 – Defining Your Own Custom Attribute

You can use predefined attributes to attach metadata to type members.

You can also define a custom attribute by creating a new class inheriting from System.Attribute.  The class name must end in “Attribute”.  You typically define a constructor that takes arguments that consist of the metadata that you want to attach to the type member.

    /// <summary>
    /// Attach to a class method to indicate kg of methane that is
    /// output when calling the method.
    /// </summary>
    public class MethaneFootprintAttribute : Attribute
    {
        public double kgMethane;

        public MethaneFootprintAttribute(int kg)
        {
            kgMethane = kg;
        }
    }

You can use the new attribute to attach metadata to individual type members.  You use the name of the new class, without the trailing “Attribute”.

        [MethaneFootprint(45)]
        public void FeedCowInBarn()
        {
            Console.WriteLine("Cow eats slop in dim confines of barn");
        }

        [MethaneFootprint(29)]
        public void LetGrazeOutside()
        {
            Console.WriteLine("Cow enjoys grazing and ends up healthier");
        }