¿Es posible crear un atributo que se pueda inicializar con un número variable de argumentos?
Por ejemplo:
[MyCustomAttribute(new int[3,4,5])] // this doesn't work
public MyClass ...
¿Es posible crear un atributo que se pueda inicializar con un número variable de argumentos?
Por ejemplo:
[MyCustomAttribute(new int[3,4,5])] // this doesn't work
public MyClass ...
Respuestas:
Los atributos tomarán una matriz. Aunque si controla el atributo, también puede usar params
en su lugar (que es más agradable para los consumidores, en mi opinión):
class MyCustomAttribute : Attribute {
public int[] Values { get; set; }
public MyCustomAttribute(params int[] values) {
this.Values = values;
}
}
[MyCustomAttribute(3, 4, 5)]
class MyClass { }
Su sintaxis para la creación de matrices simplemente está desactivada:
class MyCustomAttribute : Attribute {
public int[] Values { get; set; }
public MyCustomAttribute(int[] values) {
this.Values = values;
}
}
[MyCustomAttribute(new int[] { 3, 4, 5 })]
class MyClass { }
Puede hacerlo, pero no cumple con CLS:
[assembly: CLSCompliant(true)]
class Foo : Attribute
{
public Foo(string[] vals) { }
}
[Foo(new string[] {"abc","def"})]
static void Bar() {}
Muestra:
Warning 1 Arrays as attribute arguments is not CLS-compliant
Para el uso de reflexión regular, puede ser preferible tener múltiples atributos, es decir
[Foo("abc"), Foo("def")]
Sin embargo, esto no funcionará con TypeDescriptor
/ PropertyDescriptor
, donde solo se admite una única instancia de cualquier atributo (ya sea la primera o la última victoria, no recuerdo cuál).
Intenta declarar el constructor así:
public class MyCustomAttribute : Attribute
{
public MyCustomAttribute(params int[] t)
{
}
}
Entonces puedes usarlo como:
[MyCustomAttribute(3, 4, 5)]
Eso debería estar bien. De la especificación, sección 17.2:
Una expresión E es una expresión -argumento-atributo si todas las siguientes afirmaciones son verdaderas:
He aquí un ejemplo:
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
{
}
Sí, pero necesita inicializar la matriz que está pasando. Aquí hay un ejemplo de una prueba de fila en nuestras pruebas unitarias que prueba un número variable de opciones de línea de comando;
[Row( new[] { "-l", "/port:13102", "-lfsw" } )]
public void MyTest( string[] args ) { //... }
Para aprovechar la respuesta de Marc Gravell, sí, puede definir un atributo con parámetros de matriz, pero aplicar un atributo con un parámetro de matriz no es compatible con CLS. Sin embargo, simplemente definir un atributo con una propiedad de matriz es perfectamente compatible con CLS.
Lo que me hizo darme cuenta de esto fue que Json.NET, una biblioteca compatible con CLS, tiene una clase de atributo JsonPropertyAttribute con una propiedad llamada ItemConverterParameters que es una matriz de objetos.