Posso inicializar um atributo C # com uma matriz ou outro número variável de argumentos?


105

É possível criar um atributo que pode ser inicializado com um número variável de argumentos?

Por exemplo:

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

12
Você apenas tem a sintaxe errada para o array. Deve ser "new int [] {3,4,5}".
David Wengier

Respostas:


179

Os atributos terão uma matriz. Porém, se você controlar o atributo, também poderá usar params(o que é mais agradável para os consumidores, IMO):

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

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

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

Acontece que sua sintaxe para a criação de array está errada:

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

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

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

33

Você pode fazer isso, mas não é compatível com CLS:

[assembly: CLSCompliant(true)]

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

Programas:

Warning 1   Arrays as attribute arguments is not CLS-compliant

Para uso de reflexão regular, pode ser preferível ter vários atributos, ou seja,

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

No entanto, isso não funcionará com TypeDescriptor/ PropertyDescriptor, onde apenas uma única instância de qualquer atributo é suportada (a primeira ou a última vence, não consigo lembrar qual).


3
observação: vários atributos requerem um atributo AttributeUsage em seu atributo. stackoverflow.com/questions/553540/…
russau

23

Tente declarar o construtor assim:

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

Então você pode usá-lo como:

[MyCustomAttribute(3, 4, 5)]


12

Isso deve ficar bem. A partir das especificações, seção 17.2:

Uma expressão E é uma expressão de argumento de atributo se todas as seguintes afirmações forem verdadeiras:

  • O tipo de E é um tipo de parâmetro de atributo (§17.1.3).
  • Em tempo de compilação, o valor de E pode ser resolvido para um dos seguintes:
    • Um valor constante.
    • Um objeto System.Type.
    • Uma matriz unidimensional de expressões de argumento de atributo .

Aqui está um exemplo:

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
No entanto, esteja atento à conformidade com CLS
Marc Gravell

4

Sim, mas você precisa inicializar o array que está passando. Aqui está um exemplo de um teste de linha em nossos testes de unidade que testa um número variável de opções de linha de comando;

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

2

Você pode fazer isso. Outro exemplo poderia ser:

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

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

1

Para pegar carona na resposta de Marc Gravell, sim, você pode definir um atributo com parâmetros de matriz, mas aplicar um atributo com um parâmetro de matriz não é compatível com CLS. No entanto, apenas definir um atributo com uma propriedade de array é perfeitamente compatível com CLS.

O que me fez perceber isso foi que Json.NET, uma biblioteca compatível com CLS, tem uma classe de atributo JsonPropertyAttribute com uma propriedade chamada ItemConverterParameters que é uma matriz de objetos.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.