Próbowałem wiele razy, ale nadal nie jestem w stanie zrozumieć użycia atrybutów niestandardowych (przeszedłem już przez wiele linków).
Czy ktoś może mi wyjaśnić bardzo podstawowy przykład atrybutu niestandardowego z kodem?
Próbowałem wiele razy, ale nadal nie jestem w stanie zrozumieć użycia atrybutów niestandardowych (przeszedłem już przez wiele linków).
Czy ktoś może mi wyjaśnić bardzo podstawowy przykład atrybutu niestandardowego z kodem?
Odpowiedzi:
Chociaż kod służący do tworzenia niestandardowego atrybutu jest dość prosty, bardzo ważne jest, aby zrozumieć, czym są atrybuty:
Atrybuty to metadane wkompilowane w Twój program. Same atrybuty nie dodają żadnej funkcjonalności do klasy, właściwości czy modułu - tylko dane. Jednak korzystając z refleksji, można wykorzystać te atrybuty w celu stworzenia funkcjonalności.
Spójrzmy na przykład na Validation Application Block z biblioteki Enterprise Library firmy Microsoft . Jeśli spojrzysz na przykładowy kod, zobaczysz:
/// <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; }
Z powyższego fragmentu można się domyślić, że kod będzie zawsze walidowany, po każdej zmianie, zgodnie z regułami Walidatora (w przykładzie ma co najmniej 8 znaków i maksymalnie 8 znaków). Ale prawda jest taka, że Atrybut nic nie robi; jak wspomniano wcześniej, dodaje tylko metadane do właściwości.
Jednak biblioteka korporacyjna ma Validation.Validate
metodę, która zajrzy do twojego obiektu i dla każdej właściwości sprawdzi, czy zawartość narusza regułę informowaną przez atrybut.
Tak więc powinieneś myśleć o atrybutach - sposobie dodawania danych do kodu, które mogą być później wykorzystane przez inne metody / klasy / itp.
Zaczynasz od napisania klasy, która pochodzi od Attribute :
public class MyCustomAttribute: Attribute
{
public string SomeProperty { get; set; }
}
Następnie możesz udekorować wszystko (klasę, metodę, właściwość, ...) tym atrybutem:
[MyCustomAttribute(SomeProperty = "foo bar")]
public class Foo
{
}
i na koniec użyłbyś refleksji, aby go pobrać:
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
}
Możesz ograniczyć typy docelowe, do których można zastosować ten atrybut niestandardowy, używając atrybutu AttributeUsage :
/// <summary>
/// This attribute can only be applied to classes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute
Ważne informacje o atrybutach:
var value = typeof(Foo).GetCustomAttributes<MyCustomAttribute>().First().SomeProperty;
Wykorzystując / kopiując świetną odpowiedź Darina Dimitrova , oto jak uzyskać dostęp do niestandardowego atrybutu na właściwości, a nie w klasie:
Urządzony majątek [klasy Foo
]:
[MyCustomAttribute(SomeProperty = "This is a custom property")]
public string MyProperty { get; set; }
Pobieram to:
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;
}
Możesz wrzucić to do pętli i użyć odbicia, aby uzyskać dostęp do tego niestandardowego atrybutu dla każdej właściwości klasy 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
}
}
Wielkie dzięki, Darin !!
object[] attribute = propertyInfo.GetCustomAttributes(typeof(???), true);
Chcę tylko m1()
Krótka odpowiedź jest taka, aby utworzyć atrybut w c # wystarczy odziedziczyć go z klasy Attribute, tylko to :)
Ale tutaj opiszę szczegółowo atrybuty:
w zasadzie atrybuty to klasy, których możemy użyć do zastosowania naszej logiki do zestawów, klas, metod, właściwości, pól, ...
W .Net firma Microsoft udostępniła pewne predefiniowane atrybuty, takie jak atrybuty przestarzałe lub walidacyjne, takie jak ([Wymagane], [StringLength (100)], [Zakres (0, 999,99)]). Mamy również atrybuty, takie jak ActionFilters w asp.net które mogą być bardzo przydatne do zastosowania naszej pożądanej logiki do naszych kodów (przeczytaj ten artykuł o filtrach akcji, jeśli jesteś pasjonatem, aby się go uczyć)
Po drugie, możesz zastosować rodzaj konfiguracji do swojego atrybutu za pośrednictwem AttibuteUsage.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
Kiedy dekorujesz klasę atrybutu za pomocą AttributeUsage, możesz powiedzieć kompilatorowi C #, gdzie mam zamiar użyć tego atrybutu: zamierzam używać tego na klasach, w zestawach we właściwościach lub na ... i mój atrybut może być używany kilka razy na zdefiniowanych celach (klasy, zespoły, właściwości, ...) czy nie ?!
Po tej definicji atrybutów pokażę wam przykład: Wyobraź sobie, że chcemy zdefiniować nową lekcję na uniwersytecie i chcemy, aby tylko administratorzy i mistrzowie na naszej uczelni mogli zdefiniować nową lekcję, 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();
}
}
}
W prawdziwym świecie programowania być może nie używamy tego podejścia do używania atrybutów i powiedziałem to z powodu jego edukacyjnego punktu w używaniu atrybutów