Can I initialize a C# attribute with an array or other variable number of arguments?

Attributes will take an array. Though if you control the attribute, you can also use params instead (which is nicer to consumers, IMO):

class MyCustomAttribute : Attribute {
    public int[] Values { get; set; }

    public MyCustomAttribute(params int[] values) {
       this.Values = values;
    }
}

[MyCustomAttribute(3, 4, 5)]
class MyClass { }

Your syntax for array creation just happens to be off:

class MyCustomAttribute : Attribute {
    public int[] Values { get; set; }

    public MyCustomAttribute(int[] values) {
        this.Values = values;
    }
}

[MyCustomAttribute(new int[] { 3, 4, 5 })]
class MyClass { }

You can do it, but it isn't CLS compliant:

[assembly: CLSCompliant(true)]

class Foo : Attribute
{
    public Foo(string[] vals) { }
}
[Foo(new string[] {"abc","def"})]
static void Bar() {}

Shows:

Warning 1   Arrays as attribute arguments is not CLS-compliant

For regular reflection usage, it may be preferable to have multiple attributes, i.e.

[Foo("abc"), Foo("def")]

However, this won't work with TypeDescriptor/PropertyDescriptor, where only a single instance of any attribute is supported (either the first or last wins, I can't recall which).


Try declaring the constructor like this:

public class MyCustomAttribute : Attribute
{
    public MyCustomAttribute(params int[] t)
    {
    }
}

Then you can use it like:

[MyCustomAttribute(3, 4, 5)]


That should be okay. From the spec, section 17.2:

An expression E is an attribute-argument-expression if all of the following statements are true:

  • The type of E is an attribute parameter type (§17.1.3).
  • At compile-time, the value of E can be resolved to one of the following:
    • A constant value.
    • A System.Type object.
    • A one-dimensional array of attribute-argument-expressions.

Here's an example:

using System;

[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public class SampleAttribute : Attribute
{
    public SampleAttribute(int[] foo)
    {
    }
}

[Sample(new int[]{1, 3, 5})]
class Test
{
}

Yes, but you need to initialize the array that you are passing in. Here is an example from a row test in our unit tests that tests a variable number of command line options;

[Row( new[] { "-l", "/port:13102", "-lfsw" } )]
public void MyTest( string[] args ) { //... }