Cara membuat duplikat atribut yang diizinkan

96

Saya menggunakan atribut khusus yang diwarisi dari kelas atribut. Saya menggunakannya seperti ini:

[MyCustomAttribute("CONTROL")]
[MyCustomAttribute("ALT")]
[MyCustomAttribute("SHIFT")]
[MyCustomAttribute("D")]
public void setColor()
{

}

Tetapi kesalahan "Gandakan atribut 'MyCustomAttribute'" ditampilkan.
Bagaimana cara membuat atribut duplikat yang diperbolehkan?

ebattulga.dll
sumber

Jawaban:

184

Tempelkan AttributeUsageatribut ke kelas Atribut Anda (ya, seteguk itu) dan setel AllowMultipleke true:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class MyCustomAttribute: Attribute
Anton Gogolev
sumber
6
Hanya ingin tahu - mengapa kelas "tersegel"?
Tomas Aschan
18
Microsoft merekomendasikan penyegelan kelas atribut bila memungkinkan: msdn.microsoft.com/en-us/library/2ab31zeh.aspx
Anton Gogolev
3
Mengapa disegel? Singkatnya: Membuat pencarian atribut lebih cepat dan tidak memiliki pengaruh lain.
Noel Widmer
Kecuali itu menghentikan orang lain menggunakan kembali kode Anda. Perlu dicatat bahwa atribut validasi di DataAnnotations tidak disegel, yang sangat berguna karena memungkinkan untuk membuat spesialisasi dari atribut tersebut .
Neutrino
@Neutrino disegel harus digunakan setiap kali Anda tidak mengharapkan atau tidak merancang kelas Anda untuk diwarisi. Selain itu, jika warisan mungkin menjadi sumber bug, misalnya: Implementasi aman-thread.
Francisco Neto
20

AttributeUsageAttribute ;-p

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class MyAttribute : Attribute
{}

Namun, perhatikan bahwa jika Anda menggunakan ComponentModel ( TypeDescriptor), ini hanya mendukung satu contoh atribut (per jenis atribut) per anggota; refleksi mentah mendukung nomor apa pun ...

Marc Gravell
sumber
13

Solusi anton benar, tapi ada gotcha lain .

Singkatnya, kecuali atribut khusus Anda menimpa TypeId, maka mengaksesnya PropertyDescriptor.GetCustomAttributes()hanya akan mengembalikan satu contoh atribut Anda.

mcdrewski
sumber
Tapi ini bekerja melalui: var customAtt = propertyInfo.GetCustomAttributes <MyCustomAttribute> ();
oo_dev
8

Secara default, Attributes dibatasi untuk diterapkan hanya sekali ke satu bidang / properti / etc. Anda dapat melihat ini dari definisi Attributekelas di MSDN :

[AttributeUsageAttribute(..., AllowMultiple = false)]
public abstract class Attribute : _Attribute

Oleh karena itu, seperti yang telah dicatat orang lain, semua subclass dibatasi dengan cara yang sama, dan jika Anda memerlukan beberapa instance dari atribut yang sama, Anda perlu menyetel secara eksplisit AllowMultipleke true:

[AttributeUsage(..., AllowMultiple = true)]
public class MyCustomAttribute : Attribute

Pada atribut yang memungkinkan beberapa penggunaan, Anda juga harus mengganti TypeIdproperti untuk memastikan bahwa properti PropertyDescriptor.Attributes berfungsi seperti yang diharapkan. Cara termudah untuk melakukannya adalah dengan mengimplementasikan properti itu untuk mengembalikan instance atribut itu sendiri:

[AttributeUsage(..., AllowMultiple = true)]
public class MyCustomAttribute : Attribute
{
    public override object TypeId
    {
        get
        {
            return this;
        }
    }
}

(Memposting jawaban ini bukan karena yang lain salah, tetapi karena ini adalah jawaban yang lebih komprehensif / kanonik.)

Ian Kemp
sumber
3

Sebagai alternatif, pikirkan tentang mendesain ulang atribut Anda untuk memungkinkan suatu urutan.

[MyCustomAttribute(Sequence="CONTROL,ALT,SHIFT,D")]

atau

[MyCustomAttribute("CONTROL-ALT-SHIFT-D")]

lalu parsing nilainya untuk mengonfigurasi atribut Anda.

Untuk contoh ini, lihat AuthorizeAttribute di kode sumber ASP.NET MVC di www.codeplex.com/aspnet .

tvanfosson.dll
sumber
3
Bahkan dimungkinkan untuk meminta MyCustomAttributekonstruktor mengambil larik string, a string[], dengan atau tanpa paramspengubah. Kemudian bisa diterapkan dengan sintaks [MyCustom("CONTROL", "ALT", "SHIFT", "D")](dengan params).
Jeppe Stig Nielsen
2

Setelah Anda menambahkan AttributeUsage, pastikan Anda menambahkan properti ini ke kelas Attribute Anda

public override object TypeId
{
  get
  {
    return this;
  }
}
Gandar
sumber