Cara membuat atribut khusus di C #

119

Saya telah mencoba berkali-kali tetapi masih tidak dapat memahami penggunaan atribut khusus (saya telah melalui banyak tautan).

Adakah yang bisa menjelaskan kepada saya contoh yang sangat dasar dari atribut khusus dengan kode?

slash shogdhe
sumber

Jawaban:

96

Meskipun kode untuk membuat Atribut khusus cukup sederhana, sangat penting bagi Anda untuk memahami apa itu atribut:

Atribut adalah metadata yang dikompilasi ke dalam program Anda. Atribut itu sendiri tidak menambahkan fungsionalitas apa pun ke kelas, properti, atau modul - hanya data. Namun, dengan menggunakan refleksi, seseorang dapat memanfaatkan atribut tersebut untuk menciptakan fungsionalitas.

Jadi, sebagai contoh, mari kita lihat Blok Aplikasi Validasi , dari Perpustakaan Perusahaan Microsoft . Jika Anda melihat contoh kode, Anda akan melihat:

    /// <summary>
    /// blah blah code.
    /// </summary>
    [DataMember]
    [StringLengthValidator(8, RangeBoundaryType.Inclusive, 8, RangeBoundaryType.Inclusive, MessageTemplate = "\"{1}\" must always have \"{4}\" characters.")]
    public string Code { get; set; }

Dari potongan di atas, orang mungkin menebak bahwa kode akan selalu divalidasi, setiap kali diubah, sesuai dengan aturan Validator (dalam contoh, memiliki setidaknya 8 karakter dan paling banyak 8 karakter). Tetapi kenyataannya adalah bahwa Atribut tidak melakukan apa-apa; seperti yang disebutkan sebelumnya, ini hanya menambahkan metadata ke properti.

Namun, Enterprise Library memiliki Validation.Validatemetode yang akan melihat objek Anda, dan untuk setiap properti, akan memeriksa apakah konten melanggar aturan yang diinformasikan oleh atribut.

Jadi, begitulah seharusnya Anda memikirkan atribut - cara untuk menambahkan data ke kode Anda yang mungkin nantinya digunakan oleh metode / kelas / dll.

Bruno Brant
sumber
Akankah saya sangat menyukai jawabannya dan khususnya ", satu pertanyaan lagi saya dapat menempatkan kondisi yang sama dalam pernyataan set kode di atas jadi bagaimana perbedaannya dengan atribut,
slash shogdhe
1
@slash: Bisakah Anda mengulanginya? Saya tidak begitu mengerti pertanyaan itu.
Bruno Brant
1
Saya pikir garis miring dimaksudkan untuk menanyakan tentang perbedaan antara menggunakan atribut dan meletakkan kode validasi aktual di dalam penyetel properti. Jawaban: Meskipun menulis kode di dalam penyetel dapat dilakukan untuk memvalidasi nilai, menggunakan atribut saja tidak akan melakukan validasi seperti itu. Atribut hanyalah "meta-data". Kode lain di tempat lain harus tertarik dengan atribut yang Anda gunakan, membacanya, dan melakukan tindakan berdasarkan atribut tersebut. Contoh tipikal adalah pustaka validasi, seperti yang disebutkan @BrunoBrant.
romar
10
Tidak yakin mengapa ini adalah jawaban yang diterima. Pertanyaan sebenarnya (yang juga diindeks di Google) adalah "Bagaimana cara membuat atribut khusus di C #". Jawabannya sama sekali tidak membahas topik itu. Sebaliknya, jawaban kedua ya.
Drakestar
Saya rasa jawaban kedua lebih terkait dengan pertanyaan.
Mohammad Taherian
267

Anda mulai dengan menulis kelas yang berasal dari Atribut :

public class MyCustomAttribute: Attribute
{
    public string SomeProperty { get; set; }
}

Kemudian Anda bisa mendekorasi apa saja (class, method, property, ...) dengan atribut ini:

[MyCustomAttribute(SomeProperty = "foo bar")]
public class Foo
{

}

dan akhirnya Anda akan menggunakan refleksi untuk mengambilnya:

var customAttributes = (MyCustomAttribute[])typeof(Foo).GetCustomAttributes(typeof(MyCustomAttribute), true);
if (customAttributes.Length > 0)
{
    var myAttribute = customAttributes[0];
    string value = myAttribute.SomeProperty;
    // TODO: Do something with the value
}

Anda dapat membatasi jenis target tempat atribut khusus ini dapat diterapkan menggunakan atribut AttributeUsage :

/// <summary>
/// This attribute can only be applied to classes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute

Hal penting yang perlu diketahui tentang atribut:

  • Atribut adalah metadata.
  • Mereka dimasukkan ke dalam perakitan pada waktu kompilasi yang memiliki implikasi yang sangat serius tentang bagaimana Anda dapat mengatur propertinya. Hanya nilai konstan (diketahui pada waktu kompilasi) yang diterima
  • Satu-satunya cara untuk memahami dan menggunakan atribut khusus adalah dengan menggunakan Refleksi . Jadi, jika Anda tidak menggunakan refleksi pada waktu proses untuk mengambilnya dan menghias sesuatu dengan atribut khusus, jangan berharap banyak yang terjadi.
  • Waktu pembuatan atribut tidak deterministik. Mereka dipakai oleh CLR dan Anda sama sekali tidak memiliki kendali atasnya.
Darin Dimitrov
sumber
3
Di mana, di fungsi / kelas mana, saya harus `menggunakan refleksi untuk mengambilnya`
Hasan A Yousef
@Hasan A Yousef, misalnya pada Entity Framework terdapat atribut "Key" yang menyatakan pada framework: Properti ini harus dianggap sebagai Primary Key. Dalam membuat ORM, atribut sangat membantu
Parsa
Bagaimana Anda mengakses atribut khusus pada properti dan bukan kelas?
Kanvas
docs.microsoft.com/en-us/dotnet/standard/attributes/… hanya untuk kelengkapan, halaman msdn ini merangkumnya dengan sangat baik
Barış Akkurt
Dengan obat generik, jauh lebih mudah untuk mendapatkan jenisnya:var value = typeof(Foo).GetCustomAttributes<MyCustomAttribute>().First().SomeProperty;
jpaugh
27

Memanfaatkan / Menyalin respons bagus Darin Dimitrov , berikut adalah cara mengakses atribut khusus pada properti dan bukan kelas:

Properti yang didekorasi [kelas Foo]:

[MyCustomAttribute(SomeProperty = "This is a custom property")]
public string MyProperty { get; set; }

Mengambilnya:

PropertyInfo propertyInfo = typeof(Foo).GetProperty(propertyToCheck);
object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
if (attribute.Length > 0)
{
    MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
    string propertyValue = myAttribute.SomeProperty;
}

Anda dapat melempar ini dalam satu putaran dan menggunakan refleksi untuk mengakses atribut khusus ini pada setiap properti kelas Foo, juga:

foreach (PropertyInfo propertyInfo in Foo.GetType().GetProperties())
{
    string propertyName = propertyInfo.Name;

    object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
    // Just in case you have a property without this annotation
    if (attribute.Length > 0)
    {
        MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
        string propertyValue = myAttribute.SomeProperty;
        // TODO: whatever you need with this propertyValue
    }
}

Terima kasih banyak untukmu, Darin !!

Hopper
sumber
bagaimana kita memperluas ini jika kita tidak tahu tipe atribut apa yang ada pada properti? object[] attribute = propertyInfo.GetCustomAttributes(typeof(???), true);Saya hanya ingin mengulang semuanya dan memanggil metode m1()dari setiap atribut yang tidak diketahui
heyNow
0

Jawaban singkatnya adalah untuk membuat atribut di c # Anda hanya perlu mewarisinya dari kelas Atribut, Hanya ini :)

Tapi di sini saya akan menjelaskan atribut secara detail:

pada dasarnya atribut adalah kelas yang dapat kita gunakan untuk menerapkan logika kita ke rakitan, kelas, metode, properti, bidang, ...

Di .Net, Microsoft telah menyediakan beberapa Atribut yang telah ditentukan sebelumnya seperti Atribut Kedaluwarsa atau Validasi seperti ([Wajib], [Panjang String (100)], [Rentang (0, 999,99)]), juga kami memiliki jenis atribut seperti ActionFilters di asp.net yang bisa sangat berguna untuk menerapkan logika yang kita inginkan ke kode kita (baca artikel ini tentang filter tindakan jika Anda ingin mempelajarinya)

satu sama lain, Anda dapat menerapkan semacam konfigurasi pada atribut Anda melalui AttibuteUsage.

  [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]

Ketika Anda mendekorasi kelas atribut dengan AttributeUsage, Anda dapat memberi tahu c # compiler di mana saya akan menggunakan atribut ini: Saya akan menggunakan ini di kelas, pada rakitan pada properti atau di ... dan atribut saya diizinkan untuk digunakan beberapa kali pada target yang ditentukan (kelas, rakitan, properti, ...) atau tidak ?!

Setelah definisi tentang atribut ini, saya akan menunjukkan kepada Anda sebuah contoh: Bayangkan kita ingin mendefinisikan pelajaran baru di universitas dan kita ingin mengizinkan hanya admin dan master di universitas kita untuk menentukan Pelajaran baru, Ok?

namespace ConsoleApp1
{
    /// <summary>
    /// All Roles in our scenario
    /// </summary>
    public enum UniversityRoles
    {
        Admin,
        Master,
        Employee,
        Student
    }

    /// <summary>
    /// This attribute will check the Max Length of Properties/fields
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
    public class ValidRoleForAccess : Attribute
    {
        public ValidRoleForAccess(UniversityRoles role)
        {
            Role = role;
        }
        public UniversityRoles Role { get; private set; }

    }


    /// <summary>
    /// we suppose that just admins and masters can define new Lesson
    /// </summary>
    [ValidRoleForAccess(UniversityRoles.Admin)]
    [ValidRoleForAccess(UniversityRoles.Master)]
    public class Lesson
    {
        public Lesson(int id, string name, DateTime startTime, User owner)
        {
            var lessType = typeof(Lesson);
            var validRolesForAccesses = lessType.GetCustomAttributes<ValidRoleForAccess>();

            if (validRolesForAccesses.All(x => x.Role.ToString() != owner.GetType().Name))
            {
                throw new Exception("You are not Allowed to define a new lesson");
            }
            
            Id = id;
            Name = name;
            StartTime = startTime;
            Owner = owner;
        }
        public int Id { get; private set; }
        public string Name { get; private set; }
        public DateTime StartTime { get; private set; }

        /// <summary>
        /// Owner is some one who define the lesson in university website
        /// </summary>
        public User Owner { get; private set; }

    }

    public abstract class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime DateOfBirth { get; set; }
    }


    public class Master : User
    {
        public DateTime HireDate { get; set; }
        public Decimal Salary { get; set; }
        public string Department { get; set; }
    }

    public class Student : User
    {
        public float GPA { get; set; }
    }



    class Program
    {
        static void Main(string[] args)
        {

            #region  exampl1

            var master = new Master()
            {
                Name = "Hamid Hasani",
                Id = 1,
                DateOfBirth = new DateTime(1994, 8, 15),
                Department = "Computer Engineering",
                HireDate = new DateTime(2018, 1, 1),
                Salary = 10000
            };
            var math = new Lesson(1, "Math", DateTime.Today, master);

            #endregion

            #region exampl2
            var student = new Student()
            {
                Name = "Hamid Hasani",
                Id = 1,
                DateOfBirth = new DateTime(1994, 8, 15),
                GPA = 16
            };
            var literature = new Lesson(2, "literature", DateTime.Now.AddDays(7), student);
            #endregion

            ReadLine();
        }
    }


}

Dalam dunia nyata pemrograman mungkin kita tidak menggunakan pendekatan ini untuk menggunakan atribut dan saya mengatakan ini karena poin edukasinya dalam menggunakan atribut

Hamid
sumber