Bisakah saya menginisialisasi atribut C # dengan array atau variabel lain dari argumen?

105

Apakah mungkin untuk membuat atribut yang dapat diinisialisasi dengan sejumlah variabel argumen?

Sebagai contoh:

[MyCustomAttribute(new int[3,4,5])]  // this doesn't work
public MyClass ...
Crono
sumber
12
Anda hanya salah sintaks untuk array. Ini harus "new int [] {3,4,5}".
David Wengier

Jawaban:

179

Atribut akan mengambil array. Meskipun jika Anda mengontrol atribut, Anda juga dapat menggunakan params(yang lebih baik bagi konsumen, IMO):

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

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

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

Sintaks Anda untuk pembuatan array kebetulan tidak aktif:

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

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

[MyCustomAttribute(new int[] { 3, 4, 5 })]
class MyClass { }
Tandai Brackett
sumber
33

Anda dapat melakukannya, tetapi tidak sesuai dengan CLS:

[assembly: CLSCompliant(true)]

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

Acara:

Warning 1   Arrays as attribute arguments is not CLS-compliant

Untuk penggunaan refleksi biasa, mungkin lebih disukai memiliki beberapa atribut, yaitu

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

Namun, ini tidak akan berfungsi dengan TypeDescriptor/ PropertyDescriptor, di mana hanya satu contoh atribut apa pun yang didukung (baik kemenangan pertama atau terakhir, saya tidak ingat yang mana).

Marc Gravell
sumber
3
catatan: beberapa atribut membutuhkan atribut AttributeUsage pada atribut Anda. stackoverflow.com/questions/553540/…
russau
23

Coba deklarasikan konstruktor seperti ini:

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

Kemudian Anda bisa menggunakannya seperti:

[MyCustomAttribute(3, 4, 5)]

Scott Dorman
sumber
12

Seharusnya tidak masalah. Dari spesifikasi, bagian 17.2:

Ekspresi E adalah atribut-argumen-ekspresi jika semua pernyataan berikut ini benar:

  • Tipe E adalah tipe parameter atribut (§17.1.3).
  • Pada waktu kompilasi, nilai E dapat diselesaikan menjadi salah satu dari berikut ini:
    • Nilai konstan.
    • Objek System.Type.
    • Array satu dimensi dari atribut-argumen-ekspresi .

Berikut contohnya:

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
sumber
5
Hati-hati terhadap kepatuhan CLS, meskipun
Marc Gravell
4

Ya, tetapi Anda perlu menginisialisasi larik yang Anda masukkan. Berikut adalah contoh dari pengujian baris dalam pengujian unit kami yang menguji sejumlah variabel opsi baris perintah;

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

Kamu bisa melakukannya. Contoh lain bisa jadi:

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

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

Untuk mendukung jawaban Marc Gravell, ya Anda dapat menentukan atribut dengan parameter array tetapi menerapkan atribut dengan parameter array tidak sesuai dengan CLS. Namun, hanya mendefinisikan atribut dengan properti array sudah sesuai dengan CLS.

Apa yang membuat saya menyadari ini adalah bahwa Json.NET, pustaka yang sesuai dengan CLS, memiliki kelas atribut JsonPropertyAttribute dengan properti bernama ItemConverterParameters yang merupakan larik objek.

TBrink
sumber