ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 150
Numărul 149 Numărul 148 Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 24
Abonament PDF

PostSharp

Radu Vunvulea
Solution Architect
@iQuest



PROGRAMARE

În ultimele săptămâni am descoperit împreună principiile de bază ale Programării Orientate pe Aspecte (AOP). Acum este timpul să vedem cum putem valorifica adevăratul potențial caracteristicile AOP utilizând PostSharp.

AOP

Înainte de a intra în subiect, să facem o scurtă recapitulare. AOP este o paradigmă de programare care are drept scop principal creșterea modularității unei aplicații. AOP încearcă să atingă acest scop prin permiterea separării aspectelor secante(cross-cutting concerns) - utilizând interceptarea diferitelor comenzi sau cereri.

În ultimele articole am descoperit cum putem utiliza AOP folosind Unity și proprietăți .NET 4.5 (RealProxy). Unity ne oferă posibilitatea de a înregistra acțiunile care pot fi executate înainte și după o acțiune specifică. Clasa RealProxy este clasa principală în jurul tuturor acestor proprietăți, care este utilizată de către framework-uri precum Unity pentru a oferi această proprietate.

Cea mai mare diferență dintre RealProxy și un stack care ne oferă AOP este din perspectiva proprietăților. Utilizarea RealProxy în mod direct ne va cere să scriem toată funcționalitatea de care avem nevoie - aceasta se poate traduce în timp, bani și mai mult cod care necesită mentenanță (în cele din urmă, nu dorim să reinventăm roata).

PostSharp

PostSharp este primul framework AOP real prezentat în această serie de articole. Până acum ne-am uitat la diferite moduri în care putem utiliza proprietățile AOP, dar fără a utiliza un stack AOP real și dedicat.

Am decis să încep cu PostSharp, deoarece atunci când ai nevoie de un framework AOP pentru un proiect real care este destul de mare și de complex, mai întâi ar trebui să îți îndrepți atenția înspre PostSharp. Este tipul de framework care îți oferă aproape toate proprietățile AOP de care ai nevoie.

De obicei, eu compar PostSharp cu ReSharper din punctul de vedere al calității produsului. Este tipul de produs care are toate proprietățile de care ai nevoie atunci când vorbești despre o proprietate specifică.

PostSharp are multe proprietăți care nu pot fi discutate într-un singur articol. În viitorul apropiat, vom studia separat fiecare dintre aceste proprietăți, dar pentru moment, vom arunca o privire asupra celor mai importante proprietăți care sunt în jurul AOP.

Proprietăți

Principalele proprietăți ale PostSharp sunt:

Threading Pattern Library - ne permite să controlăm nivelul de abstracție din jurul threading, să detectăm și să diagnosticăm blocajele, să controlăm modul în care sunt executate acțiunile pe diferite fire de execuție (threads) și poziția (în prim plan sau în fundal).

Model Pattern Library - ne oferă proprietățile complete ale AOP utilizând interfața INotifyPropertyChanged. De toate setările și de celelalte lucruri se va ocupa PostSharp. Comportamentul mai complicat poate fi implementat foarte simplu când începem să utilizăm Code Contracts.

Architecture Framework -validează diferite aspecte ale calității codului și designului, șabloane de design, relații nucleu, analiză de cod și multe altele.

Odată menționate principalele proprietăți ale PostSharp, vă prezentăm partea tehnică și modul cum putem adăuga AOP în proiectul nostru, utilizând PostSharp.

Cum funcționează

Cea mai mare diferență între PostSharp și alte soluții AOP constă în modalitatea în care se adaugă comportament la comandă (custom behaviour). În general, acest comportament se adaugă în timpul de execuție, dar nu și în cazul PostSharp. Toate anexele (hooks) sunt adăugate în timpul de compilare. Astfel, performanța nu este afectată prea mult. Bineînțeles, ca și în cazul oricărui cadru AOP, performanța este afectată puțin, dar în cazul PostSharp, performanța este aproape la fel ca și fără aceasta.

În principiu, PostSharp este o acțiune post-procesor, care ia codul care este compilat și îl modifică. Toate anexele (hooks) sunt adăugate la acest nivel. Rezultatul compilatorului este preluat de PostSharp și prelucrat.

Înainte și după

Utilizarea cea mai obișnuită a AOP este să execute o specificație înainte și după ce o metodă a proprietății este apelată (de exemplu, pentru logare). Aceasta se poate face foarte simplu utilizând PostSharp, cu câteva linii de cod.

Primul pas este să definim comportamentul pe care dorim să îl executăm în acel moment anume. Acest lucru poate fi realizat prin extinderea OnMethodBoundaryAspect. Putem să supra-reglăm OnEntry, OnSuccess și OnException. În fiecare dintre aceste metode, noi avem acces la parametri de intrare, la rezultat și așa mai departe. Noi putem chiar să modificăm rezultatul apelării.

[Serializable] 
public class FooAOPAttribute : OnMethodBoundaryAspect 
{     
    public override void OnEntry(MethodExecutionArgs args) 
    { 
        ... 
    } 
    
    public override void OnSuccess(MethodExecutionArgs args) 
    { 
		...
    } 
	
    public override void OnException(MethodExecutionArgs args) 
    { 
		...
    } 
}

Din acest moment putem utiliza acest atribut pentru a adnota toate metodele pentru care dorim să avem această proprietate. Bineînțeles, putem specifica lista metodelor și în alte feluri. Putem specifica lista metodelor din AssemblyInfo.cs, unde putem defini filtre personalizate pentru metodele pentru care am dori să avem această proprietate.

Injectare de cod

Această proprietate ne permite să adăugăm cod la clasa noastră în timpul perioadei de rulare. Utilizând un atribut personalizat sau de la AssemblyInfo.cs, putem injecta cod specific în clasa noastră. De exemplu, putem specifica ca o clasă să implementeze o interfață specifică sau putem injecta o metodă specifică de proprietăți.

În exemplul de mai jos, vom descoperi cum putem injecta o proprietate specifică în clasa noastră.

[Serializable] 
public class FooAOPAspect : InstanceLevelAspect 
{ 
    public string FirstName { get; set; } 
}

[IntroduceMember] 
public string FirstName { get; set; }

[FooAOPAspect] 
public class Student 
{ 

}

Codul IL care va fi generat va conține în interior proprietatea FirstName.

INotifyPropertyChange

Când lucrăm pe un desktop sau pe o aplicație nativă, trebuie să folosim această interfață pentru a putea primi notificații atunci când valoarea proprietății este modificată (pe UI sau în cod). De obicei, aceasta se face prin implementarea interfeței de mai sus. Pentru a nu complica prea mult codul, o clasă de bază este creată atunci când este adăugată funcția de notificare.

Pentru un cod mic, aceasta este acceptabilă, dar dacă ai o aplicație complicată, ai adăuga mult cod duplicat pentru a susține această proprietate.

PostSharp rezolvă această problemă pentru noi, prin NotifyPropertyChangedAttribute. Odată ce adăugăm această proprietate clasei noastre prin Smart Tag, nu va mai trebui să ne facem griji în privința notificărilor. PostSharp se va ocupa de restul.

[NotifyPropertyChanged] 
public class StudentEdit 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string FullName  
    {  
        get 
		{ 
			return FirstName + LastName); 
		}  
    }     
    public string Email { get; set; } 
}

Ceea ce mi-a plăcut a fost suportul Transitive Dependencies. Aceasta înseamnă că, dacă valoarea FirstName este modificată, se va declanșa o notificare și pentru FullName.

Dacă dorim să adăugăm un atribut specific tuturor claselor noastre dintr-un spațiu de nume (namespace), putem să o facem relativ ușor prin utilizarea atributului multicasting. Acest lucru se face direct în fișierul AssemblyInfo.cs și ne va permite să specificăm pentru care clase este nevoie să adăugăm un atribut anume. Avem posibilitatea de a adăuga filtre, de a exclude anumite clase și așa mai departe. Bineînțeles, această setare multicasting poate fi făcută și direct din cod, utilizând IAspectProvider.

Ultimul lucru pe care trebuie să îl știți în legătură cu aceasta este că mai aveți de asemenea și alte atribute care pot fi utilizate pentru a ignora anumite proprietăți sau pentru a trata notificările într-un mod personal.

Code Contracts

După cum ne spune numele, Code Contracts (Contractele codului) ne oferă posibilitatea de a defini un acord la nivelul codului între apelare și metoda proprietății care este apelată. În acest fel, validarea input-ului nu va mai trebui să fie făcută cu un IF (dacă) personalizat. Este destul de asemănătoare cu validarea care poate fi făcută prin ActionFilter și atributele de validare din MVC, de exemplu. Avantajul este că putem defini acest acord la orice nivel, de exemplu atunci când expunem o bibliotecă API.

Cel mai simplu exemplu este verificarea NULL. De obicei, când dorim să facem o verificare NULL, adăugăm un IF (dacă) în metoda/proprietatea noastră și dăm o excepție când valoarea nu este NULL. Același lucru poate fi făcut dacă utilizăm atributul Required.

Vezi exemplul de mai jos:

public class Student
{
	public void SetLastName([Required] string newLastName)
	{
		...
	}
}

Fără PostSharp ar trebui să verificăm în corpul mesajului valoarea input și să dăm o excepție. Imaginați-vă cum ar fi să scrieți același cod de 1000 de ori. Acest tip de atribute pot fi folosite și la nivelul proprietății sau al câmpului. Un lucru interesant este atunci când le folosim la valoarea câmpului. Atunci când setăm această valoare la valoarea câmpului sau a proprietății, nu este important de unde este setată valoarea (de exemplu, dintr-o altă metodă), verificarea pentru NULL va fi făcută.

public class Student
{
	[Required]
	private string _lastName = "Default"

	public void SetLastName(string newLastName)
	{
		_lastName = newLastName;
	}
	
	public string LastName
	{
		get { return _lastName; }
		set { _lastName = value; }
	}

	public void SetFullName(string newFullName)
	{
		...
		_lastName = lastName;
	}
}

O parte din acțiunile de validare default sunt deja definite. Oricând, noi putem defini propria noastră validare la comandă, prin implementarea ILocationValidationAspect. Avem metoda ValidateValue de care avem nevoie pentru a implementa, unde putem să facem validarea noastră personalizată.

Alte proprietăți

Mai sunt și alte proprietăți grozave pe care încă nu le-am discutat, de la cea care ne permite să interceptăm evenimente, aspect compus, injectare de cod, tratarea excepțiilor, securitate, persistență obiect și multe altele. O altă proprietate care îmi place la PostSharp este posibilitatea de a specifica faptul că o interfață nu poate fi implementată de către alte ansambluri și poate fi doar utilizată.

Vă invit pe toți să vizitați web site-ul PostSharp și să îl încercați.

Licențe și costuri

Există trei tipuri de licențe PostSharp. Pentru uz individual, puteți folosi cu succes versiunea Express, care este foarte bună dacă doriți să învățați și să înțelegeți cum funcționează PostSharp.

Pe lângă versiunea Express, mai există cea Professional și Ultimate, care vin cu alte proprietăți care pot fi utilizate cu succes în producție.

Nu uitați că modelul cu licență este per dezvoltator și nu per produse dezvoltate, ceea ce înseamnă că puteți utiliza aceeași licență pentru 1 sau 100 de proiecte.

Concluzie

Bineînțeles că toate aceste proprietăți pot fi implementate de către noi, dar PostSharp ne oferă toate aceste lucruri de-a gata. Este un stack AOP utilizat în întreaga lume, extrem de matur și de bun.

În aceeaşi ediţie ... (24)

▼ TOATE ARTICOLELE ▼

NUMĂRUL 149 - Development with AI

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects