Я пробовал много раз, но все еще не могу понять использование настраиваемых атрибутов (я уже просмотрел много ссылок).
Может ли кто-нибудь объяснить мне очень простой пример настраиваемого атрибута с кодом?
Я пробовал много раз, но все еще не могу понять использование настраиваемых атрибутов (я уже просмотрел много ссылок).
Может ли кто-нибудь объяснить мне очень простой пример настраиваемого атрибута с кодом?
Ответы:
Хотя код для создания настраиваемого атрибута довольно прост, очень важно понимать, что такое атрибуты:
Атрибуты - это метаданные, скомпилированные в вашу программу. Сами атрибуты не добавляют функциональности классу, свойству или модулю - только данные. Однако, используя отражение, можно использовать эти атрибуты для создания функциональности.
Так, например, давайте посмотрим на блок приложения проверки из корпоративной библиотеки Microsoft . Если вы посмотрите на пример кода, вы увидите:
/// <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()
каждого неизвестного атрибута
Короткий ответ - для создания атрибута в С # вам нужно только наследовать его от класса Attribute, только это :)
Но здесь я собираюсь подробно объяснить атрибуты:
в основном атрибуты - это классы, которые мы можем использовать для применения нашей логики к сборкам, классам, методам, свойствам, полям, ...
В .Net Microsoft предоставила некоторые предопределенные атрибуты, такие как устаревшие или атрибуты проверки, такие как ([Required], [StringLength (100)], [Range (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();
}
}
}
В реальном мире программирования, возможно, мы не используем этот подход для использования атрибутов, и я сказал это из-за его образовательного смысла в использовании атрибутов.