Positional and Named Parameters for Attributes


In the previous example, CommentAttribute was initialized by passing a parameter to its constructor. This is the normal syntax of C# class instantiation. This form of parameter is referred to as a positional parameter. It may be thus inferred that there is an alternative way to pass parameters to constructors of attribute classes. This alternative mechanism is referred to as named parameters; whereby, parameters are assigned initial values by using their names.

A named parameter is supported by either a public field or a public property of the target attribute class. Such a property must be read/write and non-static. A named parameter is given a value via an assignment statement located after the positional parameters in the parameter list of an attribute constructor. The general form is shown below.

[attribute-name(positional-parameter-list, named-parameter1=value1, named-parameter2=value2, ...)]

When they exist, the positional parameters come first. After that, each named parameter is assigned a value and each of these is separated by commas. The order of the named parameters is unimportant. The previous example has been updated to form the next version of the CommentAttribute class shown below.

[AttributeUsage(AttributeTargets.All)]
public class CommentAttribute : Attribute
{
    string c;
    string e;

    public CommentAttribute(string s) { c = s; e = "None"; }

    public string Comment
    {
        get
        {
            return c;
        }
    }

    public string Extra
    {
        get
        {
            return e;
        }
        set
        {
            e = value;
        }
    }
}

The constructor intializes the value of the new field e to "None". No way exists of using the constructor to supply the new field a different value. However, named parameters can be used to apply a specified value to the field e (or to the property Extra in this case).

[CommentAttribute("This attribute is attached to a class declaration.",
                  Extra="This is extra information")]
class X { }

Putting this code into an example yields the following code.

// Runtime11 - Named Parameters in Attributes

using System;

[AttributeUsage(AttributeTargets.All)]
public class CommentAttribute : Attribute
{
    string c;
    string e;

    public CommentAttribute(string s) { c = s; e = "None"; }

    public string Comment
    {
        get
        {
            return c;
        }
    }

    public string Extra
    {
        get
        {
            return e;
        }
        set
        {
            e = value;
        }
    }
}

[CommentAttribute("This attribute is attached to a class declaration.",
                   Extra = "This is some extra information")]
class X { }

class Program
{
    static void Main()
    {
        Type t = typeof(X);
        
        CommentAttribute ca = (CommentAttribute)Attribute.GetCustomAttribute(t, typeof(CommentAttribute));

        Console.WriteLine("Comment is: {0}", ca.Comment);
        
        Console.WriteLine("Comment Extra is: {0}", ca.Extra);
    }
}

The output of the program is shown below.

Comment is: This attribute is attached to a class declaration.
Comment Extra is: This is some extra information