Чи можу я ініціалізувати атрибут C # з масивом або іншою змінною кількістю аргументів?


105

Чи можливо створити атрибут, який можна ініціалізувати зі змінною кількістю аргументів?

Наприклад:

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

12
У вас просто неправильний синтаксис для масиву. Це має бути "new int [] {3,4,5}".
Девід Венг'є

Відповіді:


178

Атрибути візьмуть масив. Хоча якщо ви керуєте атрибутом, ви також можете використовувати 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 { }

33

Ви можете це зробити, але це не сумісно з 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
Примітка: для декількох атрибутів потрібен атрибут AttributeUsage для вашого атрибута. stackoverflow.com/questions/553540 / ...
russau

23

Спробуйте оголосити конструктор так:

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

Тоді ви можете використовувати його так:

[MyCustomAttribute(3, 4, 5)]


12

Це повинно бути гаразд. З специфікації, розділ 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
Хоча
слідкуйте

4

Так, але вам потрібно ініціалізувати масив, який ви передаєте. Ось приклад тесту рядків у наших одиницях тестів, який тестує змінну кількість параметрів командного рядка;

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

2

Ви можете це зробити. Іншим прикладом може бути:

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

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

1

Щоб повернути відповідь Марка Гравелла, так, ви можете визначити атрибут з параметрами масиву, але застосування атрибута з параметром масиву не відповідає CLS. Однак просто визначення атрибута з властивістю масиву ідеально сумісне з CLS.

Я зрозумів це: Json.NET, бібліотека, сумісна з CLS, має клас атрибутів JsonPropertyAttribute з властивістю під назвою ItemConverterParameters, що є масивом об'єктів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.