Czy jest możliwe utworzenie atrybutu, który można zainicjować ze zmienną liczbą argumentów?
Na przykład:
[MyCustomAttribute(new int[3,4,5])] // this doesn't work
public MyClass ...
Czy jest możliwe utworzenie atrybutu, który można zainicjować ze zmienną liczbą argumentów?
Na przykład:
[MyCustomAttribute(new int[3,4,5])] // this doesn't work
public MyClass ...
Odpowiedzi:
Atrybuty przyjmą tablicę. Chociaż jeśli kontrolujesz atrybut, możesz również użyć params
zamiast niego (co jest przyjemniejsze dla konsumentów, IMO):
class MyCustomAttribute : Attribute {
public int[] Values { get; set; }
public MyCustomAttribute(params int[] values) {
this.Values = values;
}
}
[MyCustomAttribute(3, 4, 5)]
class MyClass { }
Twoja składnia tworzenia tablic po prostu jest wyłączona:
class MyCustomAttribute : Attribute {
public int[] Values { get; set; }
public MyCustomAttribute(int[] values) {
this.Values = values;
}
}
[MyCustomAttribute(new int[] { 3, 4, 5 })]
class MyClass { }
Możesz to zrobić, ale nie jest to zgodne z CLS:
[assembly: CLSCompliant(true)]
class Foo : Attribute
{
public Foo(string[] vals) { }
}
[Foo(new string[] {"abc","def"})]
static void Bar() {}
Przedstawia:
Warning 1 Arrays as attribute arguments is not CLS-compliant
W przypadku regularnego używania odbić może być preferowane posiadanie wielu atrybutów, np
[Foo("abc"), Foo("def")]
Jednak to nie zadziała z TypeDescriptor
/ PropertyDescriptor
, gdzie obsługiwane jest tylko jedno wystąpienie dowolnego atrybutu (pierwsze lub ostatnie wygrywa, nie pamiętam, który).
Spróbuj zadeklarować konstruktora w następujący sposób:
public class MyCustomAttribute : Attribute
{
public MyCustomAttribute(params int[] t)
{
}
}
Następnie możesz go używać tak:
[MyCustomAttribute(3, 4, 5)]
To powinno być w porządku. Ze specyfikacji, sekcja 17.2:
Wyrażenie E jest wyrażeniem atrybut-argument, jeśli wszystkie poniższe stwierdzenia są prawdziwe:
Oto przykład:
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
{
}
Tak, ale musisz zainicjować przekazywaną tablicę. Oto przykład z testu wiersza w naszych testach jednostkowych, który testuje zmienną liczbę opcji wiersza poleceń;
[Row( new[] { "-l", "/port:13102", "-lfsw" } )]
public void MyTest( string[] args ) { //... }
Wracając do odpowiedzi Marca Gravella, tak, możesz zdefiniować atrybut z parametrami tablicy, ale zastosowanie atrybutu z parametrem tablicy nie jest zgodne z CLS. Jednak samo zdefiniowanie atrybutu za pomocą właściwości tablicy jest całkowicie zgodne z CLS.
Uświadomiłem sobie, że Json.NET, biblioteka zgodna z CLS, ma klasę atrybutów JsonPropertyAttribute z właściwością o nazwie ItemConverterParameters, która jest tablicą obiektów.