Могу ли я инициализировать атрибут C # массивом или другим переменным числом аргументов? - PullRequest
95 голосов
/ 06 ноября 2008

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

Например:

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

Ответы [ 7 ]

164 голосов
/ 06 ноября 2008

Атрибуты будут принимать массив. Хотя если вы управляете атрибутом, вы также можете использовать 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 { }
31 голосов
/ 07 ноября 2008

Вы можете сделать это, но это не соответствует 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, где поддерживается только один экземпляр любого атрибута (первый или последний выигрыш, я не могу вспомнить, какой).

21 голосов
/ 06 ноября 2008

Попробуйте объявить конструктор так:

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

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

[MyCustomAttribute(3, 4, 5)]

12 голосов
/ 06 ноября 2008

Это должно быть хорошо. Из спецификации, раздел 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
{
}
4 голосов
/ 06 ноября 2008

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

[Row( new[] { "-l", "/port:13102", "-lfsw" } )]
public void MyTest( string[] args ) { //... }
1 голос
/ 18 марта 2016

Чтобы прокомментировать ответ Марка Грэйвела, да, вы можете определить атрибут с параметрами массива, но применение атрибута с параметром массива не является CLS-совместимым. Однако простое определение атрибута с помощью свойства массива полностью соответствует CLS.

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

1 голос
/ 06 ноября 2008

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

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

[MyAttribute("hello", 2, 3.14f)]
class Program
{
    static void Main(string[] args)
    {
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...