Можно ли инициализировать атрибут С# с массивом или другим переменным числом аргументов?

Можно ли создать атрибут, который может быть инициализирован переменным числом аргументов?

Например:

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

Ответ 1

Атрибуты будут принимать массив. Хотя, если вы контролируете атрибут, вы также можете использовать params (что лучше для потребителей, IMO):

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

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

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

Ваш синтаксис для создания массива просто отключается:

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

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

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

Ответ 2

Вы можете сделать это, но это не совместимо с CLS:

[assembly: CLSCompliant(true)]

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

Показывает:

Warning 1   Arrays as attribute arguments is not CLS-compliant

Для использования регулярного отражения может быть предпочтительным иметь несколько атрибутов, то есть

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

Однако это не будет работать с TypeDescriptor/PropertyDescriptor, где поддерживается только один экземпляр любого атрибута (либо первый, либо последний выигрыш, я не могу вспомнить, что).

Ответ 3

Попробуйте объявить конструктор следующим образом:

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

Затем вы можете использовать его как:

[MyCustomAttribute(3, 4, 5)]

Ответ 4

Это должно быть хорошо. Из спецификации, раздел 17.2:

Выражение E является выражением атрибута-аргумента, если все следующие утверждения верны:

  • Тип E - тип параметра атрибута (§17.1.3).
  • Во время компиляции значение E можно решить одним из следующих:
    • Постоянное значение.
    • Объект System.Type.
    • Одномерный массив атрибутов-аргументов-выражений.

Вот пример:

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

Да, но вам нужно инициализировать массив, в котором вы проходите. Вот пример из теста строк в наших модульных тестах, который проверяет переменное количество параметров командной строки;

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

Ответ 6

Вы можете это сделать. Другим примером может быть:

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

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

Ответ 7

Чтобы ответить на ответ Марка Гравелла, да, вы можете определить атрибут с параметрами массива, но применение атрибута с параметром массива не соответствует CLS. Однако просто определение атрибута с свойством array отлично соответствует CLS.

Что заставило меня понять, что Json.NET, CLS-совместимая библиотека, имеет класс атрибута JsonPropertyAttribute с свойством ItemConverterParameters, который представляет собой массив объектов.