User Tools

Site Tools


notes:csharp:attributes

Attributes

Attributes can be applied to:

  • assemblies
  • types
  • methods
  • parameters
  • properties

Attribute usage constraints enforce correct application of a custom attribute using the AttributeUsage attribute and the AttributeTargets enum. In other words, they define the targets for a custom attribute.

Guidelines for developing custom attributes:

  • A custom attribute class has to derive from System.Attribute (directly or indirectly)
  • A custom attribute name should have a suffix “-Attribute”.
  • Properties of a custom attribute have to be read-write.

Reflecting attributes:

  • Use the Type.GetCustomAttributes method.
  • Use the static members of the Attribute class such as Attribute.IsDefined.

You can specify multiple Conditional attributes. They are combined with OR:

// A method with a Conditional attribute must have a return type of void. Also, it should not take any parameters.
[Conditional("DEBUG"), Conditional("TRACE")]
private void Check();

Examples of attribute definitions and permitted annotations:

// Attribute definition.
public class TestAttribute : System.Attribute { }
 
// Permitted annotation.
[Test]
// Attribute definition that defines a positional parameter as a constructor parameter.
public class TestAttribute : System.Attribute
{
    public TestAttribute(int order)
    {
        this.order = order;
    }
 
    private int order;
}
 
// Permitted annotations.
[Test(1)]
[Test(12)] etc.
// Attribute definition that defines an optional named argument as a public read/write property:
public class TestAttribute : System.Attribute
{
    public bool Descending {get; set;}
 
    public TestAttribute(int order)
    {
        this.order = order;
    }
 
    private int order;
}
 
// Permitted annotations.
[Test(1, Descending = true)]
[Test(8)] etc.

Example: Define a custom attribute TestDescriptionAttribute and apply it to a class TestClass:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
public class TestDescriptionAttribute : System.Attribute
{
    private string description;
    public string Description
    {
        get { return description; }
        set { description = value; }
    }
 
    public TestDescriptionAttribute() { }
 
    // This ctor takes a string as a parameter. As a result we are able to pass a string to
    // our attribute: [TestDescription("string")]
    public TestDescriptionAttribute(string desc)
    {
        description = desc;
    }
}
...
[TestDescription("This is class description.")]
public class TestClass { }

Example: Check if a class TestClass has the Serializable attribute applied:

if (Attribute.IsDefined(typeof(TestClass), typeof(SerializableAttribute)))
{
    // ...
}
...
[Serializable]
class TestClass { }

Example: Obtain all attributes applied to the TestClass that are of type TestAttribute:

IEnumerable<CustomAttributeData> attrs = typeof(TestClass).GetType().GetCustomAttributes(TestAttribute);
...
[Test]
class TestClass { }

Example: Obtain an instance of ConditionalAttribute and examine its ConditionString property:

MethodInfo info = typeof(TestClass).GetMethod("TestMethod");
 
if (Attribute.IsDefined(info, typeof(ConditionalAttribute)))
{
    ConditionalAttribute attr =
        (ConditionalAttribute)Attribute.GetCustomAttribute(info, typeof(ConditionalAttribute));
 
    if (attr != null)
        Console.WriteLine(attr.ConditionString); // DEBUG
}
...
class TestClass
{
    [Conditional("DEBUG")]
    public void TestMethod(string s) { }
}

Example: Obtain assembly-level attributes AssemblyCompanyAttribute and AssemblyTitleAttribute:

string assemblyCompany =
    ((AssemblyCompanyAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(),
        typeof(AssemblyCompanyAttribute), false)).Company;
string assemblyTitle =
    ((AssemblyTitleAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(),
        typeof(AssemblyTitleAttribute), false)).Title;
notes/csharp/attributes.txt · Last modified: 2019/01/31 by leszek