Posso inizializzare un attributo C # con un array o un altro numero variabile di argomenti?


105

È possibile creare un attributo inizializzabile con un numero variabile di argomenti?

Per esempio:

[MyCustomAttribute(new int[3,4,5])]  // this doesn't work
public MyClass ...

12
Hai solo la tua sintassi per l'array sbagliata. Dovrebbe essere "new int [] {3,4,5}".
David Wengier

Risposte:


179

Gli attributi prenderanno un array. Sebbene tu controlli l'attributo, puoi anche usare paramsinvece (che è più carino per i consumatori, IMO):

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

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

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

La tua sintassi per la creazione di array è semplicemente disattivata:

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

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

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

33

Puoi farlo, ma non è conforme a CLS:

[assembly: CLSCompliant(true)]

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

Spettacoli:

Warning 1   Arrays as attribute arguments is not CLS-compliant

Per un uso regolare della riflessione, potrebbe essere preferibile avere più attributi, ad es

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

Tuttavia, questo non funzionerà con TypeDescriptor/ PropertyDescriptor, dove è supportata solo una singola istanza di qualsiasi attributo (la prima o l'ultima vince, non ricordo quale).


3
nota: più attributi richiedono un attributo AttributeUsage sul tuo attributo. stackoverflow.com/questions/553540/...
russau

23

Prova a dichiarare il costruttore in questo modo:

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

Quindi puoi usarlo come:

[MyCustomAttribute(3, 4, 5)]


12

Dovrebbe essere ok. Dalle specifiche, sezione 17.2:

Un'espressione E è un'espressione di attributo-argomento se tutte le seguenti affermazioni sono vere:

  • Il tipo di E è un tipo di parametro attributo (§17.1.3).
  • In fase di compilazione, il valore di E può essere risolto in uno dei seguenti:
    • Un valore costante.
    • Un oggetto System.Type.
    • Una matrice unidimensionale di espressioni di attributi-argomenti .

Ecco un esempio:

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
{
}

5
Attenzione però alla conformità al CLS
Marc Gravell

4

Sì, ma è necessario inizializzare l'array che si sta passando. Di seguito è riportato un esempio di un test di riga nei nostri test unitari che verifica un numero variabile di opzioni della riga di comando;

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

2

Ce la puoi fare. Un altro esempio potrebbe essere:

class MyAttribute: Attribute
{
    public MyAttribute(params object[] args)
    {
    }
}

[MyAttribute("hello", 2, 3.14f)]
class Program
{
    static void Main(string[] args)
    {
    }
}

1

Per tornare sulla risposta di Marc Gravell, sì, puoi definire un attributo con parametri di matrice ma l'applicazione di un attributo con un parametro di matrice non è conforme a CLS. Tuttavia, la semplice definizione di un attributo con una proprietà array è perfettamente conforme a CLS.

Ciò che mi ha fatto capire questo è stato che Json.NET, una libreria conforme a CLS, ha una classe di attributi JsonPropertyAttribute con una proprietà denominata ItemConverterParameters che è un array di oggetti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.