Is it possible to create an attribute that can be initialized with a variable number of arguments?
For example:
[MyCustomAttribute(new int[3,4,5])] // this doesn't work
public MyClass ...
Is it possible to create an attribute that can be initialized with a variable number of arguments?
For example:
[MyCustomAttribute(new int[3,4,5])] // this doesn't work
public MyClass ...
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:
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 ) { //... }
You can do that. Another example could be:
class MyAttribute: Attribute
{
public MyAttribute(params object[] args)
{
}
}
[MyAttribute("hello", 2, 3.14f)]
class Program
{
static void Main(string[] args)
{
}
}
To piggy back on Marc Gravell's answer, yes you can define an attribute with array parameters but applying an attribute with an array parameter is not CLS-compliant. However just defining an attribute with an array property is perfectly CLS-compliant.
What made me realize this was that Json.NET, a CLS-compliant library, has an attribute class JsonPropertyAttribute with a property named ItemConverterParameters that's an array of objects.
I use maybe a bit stupid workaround using this trick:
public class CLParam : Attribute
{
/// <summary>
/// Command line parameter
/// </summary>
public string Names { get; set; }
}
and then splitting the Names into string[]:
var names = loadAtt.Names.Split(',');
I allows me to use attribute like this:
class CLContext
{
[CLParam(Names = "selectscene,ss")]
public List<string> SelectScene { get; set; }
But of course for ints you would need to parse texts, so maybe a bit slow...