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?
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:
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.Validate
phươ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.
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:
var value = typeof(Foo).GetCustomAttributes<MyCustomAttribute>().First().SomeProperty;
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 !!
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õ
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