Відповіді:
Хоча код для створення спеціального атрибута досить простий, дуже важливо, щоб ви зрозуміли, що таке атрибути:
Атрибути - це метадані, зібрані у вашій програмі. Самі атрибути не додають ніякого функціоналу до класу, властивості чи модуля - лише дані. Однак, використовуючи рефлексію, можна використовувати ці атрибути для створення функціональності.
Так, наприклад, давайте подивимось на блок валідаційних програм із бібліотеки корпорацій Майкрософт . Якщо ви подивитесь на приклад коду, ви побачите:
/// <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; }
З фрагменту вище можна здогадатися, що код завжди буде підтверджений, коли він буде змінений відповідно до правил Валідатора (у прикладі має бути щонайменше 8 символів та максимум 8 символів). Але правда полягає в тому, що Атрибут нічого не робить; як було сказано раніше, вони додають лише метадані до властивості.
Однак у бібліотеці підприємств є Validation.Validate
метод, який буде вивчати ваш об’єкт, і для кожного властивості він перевірятиме, чи вміст порушує правило, повідомлене атрибутом.
Отже, саме так слід подумати про атрибути - спосіб додати дані до коду, які згодом можуть бути використані іншими методами / класами / тощо.
Ви починаєте з написання класу, який походить від Attribute :
public class MyCustomAttribute: Attribute
{
public string SomeProperty { get; set; }
}
Тоді ви можете прикрасити що-небудь (клас, метод, властивість, ...) цим атрибутом:
[MyCustomAttribute(SomeProperty = "foo bar")]
public class Foo
{
}
і, нарешті, ви б використали роздуми, щоб отримати його:
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
}
Ви можете обмежити цільові типи, до яких цей спеціальний атрибут може бути застосований за допомогою атрибута AttributeUsage :
/// <summary>
/// This attribute can only be applied to classes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute
Важливі речі, які потрібно знати про атрибути:
var value = typeof(Foo).GetCustomAttributes<MyCustomAttribute>().First().SomeProperty;
Використовуючи / копіюючи велику відповідь Даріна Димитрова , ось як отримати доступ до користувацького атрибуту для властивості, а не класу:
Оформлена власність [класу Foo
]:
[MyCustomAttribute(SomeProperty = "This is a custom property")]
public string MyProperty { get; set; }
Отримання:
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;
}
Ви можете кинути це у циклі та використовувати відображення для доступу до цього спеціального атрибуту для кожного властивості класу Foo
:
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
}
}
Велике спасибі тобі, Дарин !!
object[] attribute = propertyInfo.GetCustomAttributes(typeof(???), true);
Я просто хочу переглядати їх і називати метод m1()
кожного невідомого атрибута
Коротка відповідь - це створити атрибут в c #, вам потрібно лише успадкувати його з класу Attribute, просто це :)
Але тут я детально поясню атрибути:
в основному атрибути - це класи, які ми можемо використовувати їх для застосування нашої логіки до збірок, класів, методів, властивостей, полів, ...
У .Net, Microsoft надала такі заздалегідь задані атрибути, як застарілі або атрибути перевірки, такі як ([Потрібно], [StringLength (100)], [Діапазон (0, 999,99)])], також у нас є такі атрибути, як ActionFilters в asp.net що може бути дуже корисним для застосування бажаної логіки до наших кодів (прочитайте цю статтю про фільтри дій, якщо ви захоплені її вивченням)
З іншого боку, ви можете застосувати своєрідну конфігурацію до свого атрибуту через AttibuteUsage.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
Коли ви прикрашаєте клас атрибутів AttributeUsage, ви можете сказати c # компілятору, де я буду використовувати цей атрибут: я збираюся використовувати це на класах, на збірках щодо властивостей або на ..., і мій атрибут дозволяється використовувати кілька разів на визначені цілі (класи, збірки, властивості, ...) чи ні ?!
Після цього визначення щодо атрибутів я покажу вам приклад: Уявіть, що ми хочемо визначити новий урок в університеті, і ми хочемо дозволити просто адміністраторам і магістрам в нашому університеті визначити новий урок, добре?
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();
}
}
}
У реальному світі програмування, можливо, ми не використовуємо цей підхід для використання атрибутів, і я сказав це через його навчальний момент використання атрибутів