Tutorial „Folosirea atributelor în C#”

Tradus din această pagină oficială de documentație Microsoft.

Atributele oferă o cale de a asocia informații cu cod într-un mod declarativ. Ele pot de asemenea folosi un element reutilizabil care poate fi aplicat la o varietate de ținte.

Considerați atributul [Obsolete]. El poate fi aplicat claselor, structurilor, metodelor, constructorilor, și mai multe. El declară că elementul este învechit (en. obsolete). Apoi depinde de compilatorul C# să caute acest atribut, și să facă ceva ca răspuns.

In acest tutorial, dvs. veți fi introdus la cum să adăugați atribute codului dvs., cum să creați și să folosiți propriile dvs. atribute, și cum să folosiți unele atribute care sunt construite în .NET Core.

Cerințe preliminare

Dvs. va trebui să vă configurați mașina să ruleze .NET core. Puteți găsi instrucțiunile de instalare pe pagina .NET Core. Puteți rula această aplicație pe Windows, Ubuntu Linux, macOS sau într-un container Docker. Dvs. va trebui să vă instalați editorul favorit de cod al dvs. Descrierile de mai jos folosesc Visual Studio Code care este un editor cu sursă deschisă, cross-platformă. Totuși, puteți folosi oricare unelte cu care vă simțiți confortabil.

Crearea aplicației

Acum că v-ați instalat toate uneltele, creați o nouă aplicație .NET Core. Pentru a folosi generatorul din linie de comandă, executați următoarea comandă în shell-ul dvs. favorit:

dotnet new console

Această comandă va crea fișierele esențiale de proiect .NET core. Dvs. va trebui să executați dotnet restore pentru a restaura dependențele necesare pentru a compila acest proiect.

Notă. Începând cu .NET Core 2.0, nu trebuie să rulați dotnet restore deoarece este rulat în mod implicit de toate comenzile care cer o restaurare să aibă loc, cum sunt dotnet new, dotnet build și dotnet run. Este încă o comandă validă în unele scenarii unde a face o restaurare explicită are loc, cum ar fi construcții de integrare continuă în Azure DevOps Services sau în sisteme de construcție care au nevoie să controleze în mod explicit timpul la care are loc restaurarea.

Pentru a executa programul, folosiți dotnet run. Ar trebui să vedeți ieșirea „Hello, World” către consolă.

Cum adăugați atribute la cod

In C#, atributele sunt clase care moștenesc de la clasa bază Attribute. Oricare clasă care moștenește de la Attribute poate fi folosită ca un fel de „etichetă” pe alte bucăți de cod. De exemplu, există un atribut numit ObsoleteAttribute. Acesta este folosit să semnaleze că codul este învechit și trebuie să nu mai fie folosit. Puteți plasa acest atribut pe o clasă, de exemplu, folosind paranteze drepte.

[Obsolete]
public class MyClass
{

}

Notați că în timp ce clasa se cheamă ObsoleteAttribute, este necesar să folosiți doar [Obsolete] în cod. Aceasta este o convenție pe care C# o urmează. Puteți folosi numele complet [ObsoleteAttribute] dacă doriți.

Când marcați o clasă ca învechită, este o idee bună să oferiți ceva informație despre de ce este învechită, și/sau ce să se folosească în schimb. Faceți aceasta oferind un parametru șir la atributul Obsolete.

[Obsolete("ThisClass este invechita. Folositi ThisClass2 in schimb.")]
public class ThisClass
{


}

Sirul este transmis ca un argument la un constructor ObsoleteAttribute, ca și când ați scrie var attr = new ObsoleteAttribute("ceva sir").

Parametrii către un constructor de atribut sunt limitați la tipuri simple/literali: bool, int, double, string, Type, enums, etc. și vectori de aceste tipuri. Nu puteți folosi o expresie sau variabilă. Sunteți liberi să folosiți parametrii poziționali sau numiți.

Cum vă creați propriul atribut

Crearea unui atribut este atât de simplu ca moștenind de la clasa bază Attribute.

public class MySpecialAttribute : Attribute
{


}

Cu ce e deasupra, pot acum folosi [MySpecial] (sau [MySpecialAttribute]) ca un atribut altundeva în codul de bază.

[MySpecial]
public class SomeOtherClass
{


}

Atributele din biblioteca de clase bază .NET precum ObsoleteAttribute delanșează unele comportamente în compilator. Totuși, orice atribut creați acționează doar ca metadate, și nu rezultă în execuția nici unui cod în clasa atribut. Depinde de dvs. să acționați pe baza acestor metadate altundeva în codul dvs. (mai multe despre aceasta mai în târziu în tutorial).

Există un „te-am prins” aici de care să aveți grijă. După cum s-a menționat mai sus, doar unele tipuri sunt permise să fie transmise ca argumente când se folosesc atribute. Totuși, când se creează un tip atribut, compilatorul C# nu vă va opri din a crea acești parametri. In exemplul de mai jos, am creat un atribut cu un constructor care compilează bine.

public class GotchaAttribute : Attribute
{
    public GotchaAttribute(Foo myClass, string str) {
       
    }
}


Totuși, dvs. nu veți putea să folosiți acest constructor cu sintaxa de atribut.

[Gotcha(new Foo(), "test")] // nu compileaza
public class AttributeFail
{


}

Ce e mai sus va cauza o eroare de compilare precum

Attribute constructor parameter 'myClass' has type 'Foo', which is not a valid attribute parameter type

tradus „Parametrul constructorului de atribut 'myClass' are tipul 'Foo', care nu este un tip valid de parametru de atribut.”

Cum restricționați utilizarea atributului

Atributele pot fi folosite pe un anumit număr de „ținte”. Exemplele de mai sus le arată pe clase, dar ele pot de asemenea fi folosite pe:
  • ansamblu (Assembly)
  • clasă
  • constructor
  • delegat
  • enumerare
  • eveniment
  • câmp
  • parametru generic
  • interfață
  • metodă
  • modul
  • parametru
  • proprietate
  • valoare de întoarcere
  • structură
Când creați o clasă atribut, în mod implicit, C# vă va permite să folosiți acel atribut pe oricare din țintele posibile ale atributelor. Dacă doriți să restricționați atributul dvs. la anumite ținte, puteți să faceți aceasta folosind AttributeUsageAttribute pe clasa dvs. atribut. E drept, un atribut pe un atribut!

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class MyAttributeForClassAndStructOnly : Attribute
{

}

Dacă încercați să puneți atributul de mai sus pe ceva care nu este o clasă sau structură, veți primi o eroare de compilator ca Attribute 'MyAttributeForClassAndStructOnly' is not valid on this declaration type. It is only valid on 'class, struct' declarations.

public class Foo
{
    // daca atributul de mai jos era necomentat, ar fi cauzat o eroare de compilator
    // [MyAttributeForClassAndStructOnly]
    public Foo()
    { }
}

Cum folosiți atribute atașate la un element de cod

Atributele se comportă ca metadate. Fără o fortă exterioară, ele nu vor face nimic de fapt.

Pentru a le găsi și a acționa pe atribute, Reflection este în general necesar. Nu voi acoperi Reflection în profunzime în acest tutorial, dar ideea de bază este că Reflection vă permite să scrieți cod în C# care examinează alt cod.

De exemplu, dvs. puteți folosi Reflection pentru a obține informații despre o clasă:

TypeInfo typeInfo = typeof(MyClass).GetTypeInfo();
Console.WriteLine("Numele calificat de asamblare al MyClass este " + typeInfo.AssemblyQualifiedName);


Aceasta va afișa ceva precum: Numele calificat de asamblare al MyClass este ConsoleApplication.MyClass, attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

Odată ce aveți un obiect TypeInfo (sau un MemberInfo, FieldInfo, etc.), dvs. puteți folosi metoda GetCustomAttributes. Aceasta va returna o colecție de obiecte Attribute. Dvs. puteți de asemenea folosi GetCustomAttribute și specifica un tip Attribute.

Aici este un exemplu de utilizare a GetCustomAttributes pe o instanță MemberInfo pentru MyClass (pe care am văzut-o mai devreme că are un atribut [Obsolete] pe ea).

var attrs = typeInfo.GetCustomAttributes();
foreach(var attr in attrs)
    Console.WriteLine("Attribute pe MyClass: " + attr.GetType().Name);


Aceasta va tipări în consolă: Attribute pe MyClass: ObsoleteAttribute. Incrcați să adăugați alte atribute la MyClass.

Este important să notați că aceste obiecte Attribute sunt inițializate leneș. Aceasta înseamnă, ele nu vor fi inițializate până când dvs. folosiți GetCustomAttribute sau GetCustomAttributes. Ele sunt de asemenea instanțiate de fiecare dată. Apelând GetCustomAttributes de două ori la rând va întoarce două instanțe diferite ale ObsoleteAttribute.

Atribute comune în biblioteca de bază de clase (BCL)

Atributele sunt folosite de multe unelte și cadre de lucru. NUnit folosește atribute precum [Test] și [TestFixture] care sunt folosite de executorul de teste NUnit. ASP.NET MVC folosește atribute precum [Authorize] și oferă un cadru filtrare a acțiunii (en. action filter Framework) pentru a realiza aspecte intersectoriale (en. cross-cutting concerns) pe acțiuni MVC. PostSharp folosește sintaxa de atribute pentru a permite programarea orientată pe aspecte în C#.

Aici sunt câteva atribute notabile construite în bibliotecile de clase de bază ale .NET Core:
  • [Obsolete]. Acesta a fost folosit în exemplele de mai sus, și trăiește în namespace-ul System. Este folositor în a furniza documentație declarativă despre cod de bază în schimbare. Un mesaj poate fi furnizat în forma unui șir, și un alt parametru boolean poate fi folosit pentru a escalada de la o avertizare de compilator la o eroare de compilator.
  • [Conditional]. Acest atribut este în namespace-ul System.Diagnostics. Acest atribut poate fi folosit la metode (sau clase atribut). Dvs. trebuie să transmiteți un șir la constructor. Dacă acel șir se potrivește cu o directivă #define, atunci oricare apel la acea metodă (dar nu metoda însăși) va fi ștearsă de compilatorul C#. Uzual aceasta este folosită pentru scopuri de depanare (diagnosticare).
  • [CallerMemberName]. Acest atribut poate fi folosit pe parametri, și trăiește în namespace-ul System.Runtime.CompilerServices. Acesta este un atribut care este folosit pentru a injecta numele metodei care apelează altă metodă. Uzual, acesta este folosit ca o cale de a elimina 'șiruri magice' când se implementează INotifyPropertyChanged în variate cadre de lucru de interfață grafică. Ca un exemplu:
public class MyUIClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private string _name;
    public string Name
    {
        get { return _name;}
        set
        {
            if (value != _name)
            {
                _name = value;
                RaisePropertyChanged();   // notati ca nu e nevoie de "Name" aici in mod explicit
            }
        }
    }
}

In codul de mai sus, dvs. nu trebuie să aveți un șir literal "Name". Aceasta poate preveni bug-uri legate de greșeli de scriere și de asemenea ajută la o refactorizare/redenumire mai ușoară.

Sumar

Atributele aduc putere declarativă în C#. Dar ele sunt o formă de cod ca meta-date, și nu acționează prin ele însele.

Tradus din această pagină oficială de documentație Microsoft.

Niciun comentariu:

Trimiteți un comentariu