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
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 {}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With