Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What syntax is allowed when applying C# attributes?

These are the most common and only patterns I have seen so far:

[AttributeFoo]
[AttributeBar("Hello world!")]
[AttributeBaz(foo=42,bar="Hello world!")]
public class Example {}

The attribute syntax looks like you're calling a constructor. And before C# supported optional and named arguments, named parameters for attributes were the only visible difference.

Does the C# compiler allow anything else? Like params arguments or object/collection initializers?

See also: Applying Attributes on MSDN

like image 659
Michiel van Oosterhout Avatar asked Jan 18 '12 21:01

Michiel van Oosterhout


2 Answers

In addition to what others have said, I'd like to point out that attributes can also be comma separated.

[AttributeFoo, AttributeBar("Hello world!"), AttributeBaz(foo=42,bar="Hello world!")]
public class Example {}
like image 96
Trystan Spangler Avatar answered Sep 23 '22 22:09

Trystan Spangler


AFAIK, named parameters only permit integral types. Unfortunately i do not have a reference to back this up, I only learnt it through my own experimentation.

When trying to use object initialisers, I got this error from the compiler:

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

Although this documentation is a few years old, it has the reference information I was looking for:

Attribute parameters are restricted to constant values of the following types:

  • Simple types (bool, byte, char, short, int, long, float, and double)
  • string
  • System.Type
  • enums
  • object (The argument to an attribute parameter of type object must be a constant value of one of the above types.) One-dimensional arrays of any of the above types

So this works:

//Test attribute class
[AttributeUsage(AttributeTargets.All)]
internal class TestAttribute : Attribute
{
    public int[] Something { get; set; }
}

//Using an array initialiser - an array of integers
[TestAttribute(Something = new int[]{1, 2, 3, 4, 5})]
public abstract class Something

Whereas this wouldn't:

//Test person class
internal class Person
{
    public string Name { get; set; }

    public Person(string name)
    {
        this.Name = name;
    }
}

//Test attribute class
[AttributeUsage(AttributeTargets.All)]
internal class TestAttribute : Attribute
{
    public IEnumerable<Person> Something { get; set; }
}

//This won't work as Person is not an integral type
[TestAttribute(Something = new Person[]{new Person("James")})]

EDIT: just to elaborate, attributes form part of the metadata for constructs they are applied to (within the generated IL), thus the members of the attribute class must be determined at compile time; hence the restriction on attribute parameters to constant values.

like image 25
James Shuttler Avatar answered Sep 22 '22 22:09

James Shuttler