Cách tạo thuộc tính tùy chỉnh trong C #


119

Tôi đã thử rất nhiều lần nhưng vẫn không thể hiểu cách sử dụng các thuộc tính tùy chỉnh (tôi đã xem qua rất nhiều liên kết).

Có ai có thể giải thích cho tôi một ví dụ rất cơ bản về thuộc tính tùy chỉnh với mã không?

Câu trả lời:


96

Mặc dù mã để tạo Thuộc tính tùy chỉnh khá đơn giản, nhưng điều rất quan trọng là bạn phải hiểu thuộc tính là gì:

Thuộc tính là siêu dữ liệu được biên dịch vào chương trình của bạn. Bản thân các thuộc tính không thêm bất kỳ chức năng nào vào một lớp, thuộc tính hoặc mô-đun - chỉ là dữ liệu. Tuy nhiên, bằng cách sử dụng phản chiếu, người ta có thể tận dụng các thuộc tính đó để tạo ra chức năng.

Vì vậy, chẳng hạn, chúng ta hãy xem xét Khối Ứng dụng Xác thực , từ Thư viện Doanh nghiệp của Microsoft . Nếu bạn xem một ví dụ về mã, bạn sẽ thấy:

    /// <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; }

Từ đoạn mã trên, người ta có thể đoán rằng mã sẽ luôn được xác thực, bất cứ khi nào được thay đổi, theo các quy tắc của Trình xác thực (trong ví dụ: có ít nhất 8 ký tự và nhiều nhất 8 ký tự). Nhưng sự thật là Thuộc tính không làm gì cả; như đã đề cập trước đây, nó chỉ thêm siêu dữ liệu vào thuộc tính.

Tuy nhiên, Thư viện doanh nghiệp có một Validation.Validatephương thức sẽ xem xét đối tượng của bạn và đối với mỗi thuộc tính, nó sẽ kiểm tra xem nội dung có vi phạm quy tắc được thuộc tính thông báo hay không.

Vì vậy, đó là cách bạn nên nghĩ về các thuộc tính - một cách để thêm dữ liệu vào mã của bạn mà sau này có thể được sử dụng bởi các phương thức / lớp / v.v. khác.


sẽ i thực sự thích câu trả lời và đặc biệt", một câu hỏi nữa tôi có thể đặt cùng một điều kiện trong bộ tuyên bố của các mã trên vậy làm thế nào nó khác nhau từ attributs,
giảm shogdhe

1
@slash: Bạn có thể diễn đạt lại không? Tôi không hoàn toàn hiểu câu hỏi.
Bruno Brant

1
Tôi nghĩ rằng dấu gạch chéo có nghĩa là để hỏi về sự khác biệt giữa việc sử dụng các thuộc tính và đặt mã xác thực thực tế bên trong trình thiết lập thuộc tính. Trả lời: Trong khi việc viết mã bên trong bộ cài đặt có thể được thực hiện để xác thực giá trị, nhưng chỉ sử dụng các thuộc tính sẽ không thực hiện việc xác thực như vậy. Các thuộc tính chỉ là "siêu dữ liệu". Một mã khác ở nơi khác sẽ quan tâm đến các thuộc tính bạn sử dụng, đọc chúng và thực hiện các hành động dựa trên chúng. Ví dụ điển hình là thư viện xác thực, như @BrunoBrant đã đề cập.
romar

10
Không chắc tại sao đây là câu trả lời được chấp nhận. Câu hỏi thực tế (cũng được lập chỉ mục trong Google) là "Làm thế nào để tạo một thuộc tính tùy chỉnh trong C #". Các câu trả lời hoàn toàn không đi sâu vào chủ đề đó. Mặt khác, câu trả lời thứ 2 thì có.
Drakestar,

Tôi nghĩ câu trả lời thứ hai liên quan nhiều hơn đến câu hỏi.
Mohammad Taherian

267

Bạn bắt đầu bằng cách viết một lớp dẫn xuất từ Thuộc tính :

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

Sau đó, bạn có thể trang trí bất kỳ thứ gì (lớp, phương thức, thuộc tính, ...) với thuộc tính này:

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

}

và cuối cùng bạn sẽ sử dụng phản chiếu để tìm nạp nó:

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
}

Bạn có thể giới hạn các loại mục tiêu mà thuộc tính tùy chỉnh này có thể được áp dụng bằng cách sử dụng thuộc tính AttributeUsage :

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

Những điều quan trọng cần biết về thuộc tính:

  • Thuộc tính là siêu dữ liệu.
  • Chúng được đưa vào assembly tại thời điểm biên dịch, điều này có ý nghĩa rất nghiêm trọng về cách bạn có thể thiết lập các thuộc tính của chúng. Chỉ các giá trị không đổi (đã biết tại thời điểm biên dịch) được chấp nhận
  • Cách duy nhất để hiểu và sử dụng các thuộc tính tùy chỉnh là sử dụng Reflection . Vì vậy, nếu bạn không sử dụng phản chiếu trong thời gian chạy để tìm nạp chúng và trang trí thứ gì đó bằng thuộc tính tùy chỉnh thì không mong đợi nhiều điều xảy ra.
  • Thời gian tạo ra các thuộc tính là không xác định. Chúng được khởi tạo bởi CLR và bạn hoàn toàn không có quyền kiểm soát nó.

3
Trong trường hợp, trong đó chức năng / lớp thì tôi `sử dụng phản ánh để lấy it`
Hasan Một Yousef

@Hasan A Yousef, ví dụ trong Entity Framework có thuộc tính "Key" nói với framework: Thuộc tính này nên được hiểu là Khóa chính. Trong việc tạo ra ORM, thuộc tính này là rất hữu ích
Parsa

Làm cách nào để bạn truy cập một thuộc tính tùy chỉnh trên một thuộc tính chứ không phải một lớp?
Canvas

docs.microsoft.com/en-us/dotnet/standard/attributes/… chỉ để đầy đủ, trang msdn này tóm tắt nó rất tốt
Barış Akkurt

Với generic, việc lấy các loại dễ dàng hơn rất nhiều:var value = typeof(Foo).GetCustomAttributes<MyCustomAttribute>().First().SomeProperty;
jpaugh

27

Sử dụng / sao chép phản hồi tuyệt vời của Darin Dimitrov , đây là cách truy cập một thuộc tính tùy chỉnh trên một thuộc tính chứ không phải một lớp:

Thuộc tính được trang trí [của lớp Foo]:

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

Tìm nạp nó:

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;
}

Bạn có thể ném nó vào một vòng lặp và sử dụng phản chiếu để truy cập thuộc tính tùy chỉnh này trên từng thuộc tính của lớp Foo, cũng như:

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
    }
}

Cảm ơn chính vì bạn, Darin !!


làm thế nào chúng ta sẽ mở rộng điều này nếu chúng ta không biết những loại thuộc tính nào tồn tại trên một thuộc tính? object[] attribute = propertyInfo.GetCustomAttributes(typeof(???), true);Tôi chỉ muốn để lặp qua tất cả trong số họ và gọi một phương thức m1()của mỗi thuộc tính không rõ
heyNow

0

Câu trả lời ngắn gọn là để tạo một thuộc tính trong c #, bạn chỉ cần kế thừa nó từ lớp Thuộc tính, Chỉ thế này :)

Nhưng ở đây tôi sẽ giải thích các thuộc tính một cách chi tiết:

Về cơ bản, thuộc tính là các lớp mà chúng ta có thể sử dụng chúng để áp dụng logic của chúng ta cho các hợp ngữ, lớp, phương thức, thuộc tính, trường, ...

Trong .Net, Microsoft đã cung cấp một số Thuộc tính được xác định trước như Thuộc tính lỗi thời hoặc Xác thực như ([Bắt buộc], [StringLength (100)], [Phạm vi (0, 999.99)]), ngoài ra chúng tôi có loại thuộc tính như ActionFilters trong asp.net điều đó có thể rất hữu ích để áp dụng logic mong muốn của chúng tôi cho các mã của chúng tôi (đọc này bài viết về bộ lọc hành động nếu bạn có đam mê để tìm hiểu nó)

một điểm khác, bạn có thể áp dụng một loại cấu hình trên thuộc tính của mình thông qua AttibuteUsage.

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

Khi bạn trang trí một lớp thuộc tính với AttributeUsage, bạn có thể cho trình biên dịch c # biết nơi tôi sẽ sử dụng thuộc tính này: Tôi sẽ sử dụng thuộc tính này trên các lớp, trên các hợp ngữ trên thuộc tính hoặc trên ... và thuộc tính của tôi được phép sử dụng nhiều lần trên các mục tiêu đã xác định (lớp, hợp ngữ, thuộc tính, ...) hay không ?!

Sau định nghĩa này về các thuộc tính, tôi sẽ cho bạn xem một ví dụ: Hãy tưởng tượng chúng ta muốn xác định một bài học mới trong trường đại học và chúng ta muốn chỉ cho phép các quản trị viên và thạc sĩ trong trường đại học của chúng ta xác định một Bài học mới, 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();
        }
    }


}

Trong thế giới thực của lập trình, có thể chúng ta không sử dụng phương pháp này để sử dụng các thuộc tính và tôi đã nói điều này vì quan điểm giáo dục của nó trong việc sử dụng các thuộc tính

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.