Puis-je initialiser un attribut C # avec un tableau ou un autre nombre variable d'arguments?

105

Est-il possible de créer un attribut qui peut être initialisé avec un nombre variable d'arguments?

Par exemple:

[MyCustomAttribute(new int[3,4,5])]  // this doesn't work
public MyClass ...
Crono
la source
12
Vous avez juste une mauvaise syntaxe pour le tableau. Ce devrait être "new int [] {3,4,5}".
David Wengier

Réponses:

179

Les attributs prendront un tableau. Cependant, si vous contrôlez l'attribut, vous pouvez également utiliser à la paramsplace (ce qui est plus agréable pour les consommateurs, l'OMI):

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

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

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

Votre syntaxe pour la création de tableaux se trouve être désactivée:

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

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

[MyCustomAttribute(new int[] { 3, 4, 5 })]
class MyClass { }
Mark Brackett
la source
33

Vous pouvez le faire, mais ce n'est pas conforme CLS:

[assembly: CLSCompliant(true)]

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

Spectacles:

Warning 1   Arrays as attribute arguments is not CLS-compliant

Pour une utilisation régulière de la réflexion, il peut être préférable d'avoir plusieurs attributs, c'est-à-dire

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

Cependant, cela ne fonctionnera pas avec TypeDescriptor/ PropertyDescriptor, où une seule instance d'un attribut est prise en charge (le premier ou le dernier gagne, je ne me souviens pas lequel).

Marc Gravell
la source
3
Remarque: plusieurs attributs nécessitent un attribut AttributeUsage sur votre attribut. stackoverflow.com/questions/553540/…
russau
23

Essayez de déclarer le constructeur comme ceci:

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

Ensuite, vous pouvez l'utiliser comme:

[MyCustomAttribute(3, 4, 5)]

Scott Dorman
la source
12

Cela devrait être correct. D'après la spécification, section 17.2:

Une expression E est une expression -argument-attribut si toutes les déclarations suivantes sont vraies:

  • Le type de E est un type de paramètre d'attribut (§17.1.3).
  • Au moment de la compilation, la valeur de E peut être résolue en l'un des éléments suivants:
    • Une valeur constante.
    • Un objet System.Type.
    • Un tableau unidimensionnel d' expressions d'arguments d' attributs .

Voici un exemple:

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
{
}
Jon Skeet
la source
5
Attention toutefois à la conformité CLS
Marc Gravell
4

Oui, mais vous devez initialiser le tableau que vous transmettez. Voici un exemple tiré d'un test de ligne dans nos tests unitaires qui teste un nombre variable d'options de ligne de commande;

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

Vous pouvez le faire. Un autre exemple pourrait être:

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

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

Pour reprendre la réponse de Marc Gravell, oui, vous pouvez définir un attribut avec des paramètres de tableau, mais l'application d'un attribut avec un paramètre de tableau n'est pas conforme à CLS. Cependant, la simple définition d'un attribut avec une propriété de tableau est parfaitement conforme à CLS.

Ce qui m'a fait réaliser cela, c'est que Json.NET, une bibliothèque compatible CLS, a une classe d'attributs JsonPropertyAttribute avec une propriété nommée ItemConverterParameters qui est un tableau d'objets.

TBrink
la source