2007-01-26

.NET bästa praxis: properties

För ganska länge sedan hjälpte jag ett företag att vidareutveckla ett system på .NET-plattformen (ASP.NET, IIS, SQL Server) med ett av företaget egenutvecklat ramverk som skulle användas för alla deras webbapplikationer. Personen som hade varit "arkitekt" för ramverket kom från en Java- och Oraclebakgrund och hade ingen större erfarenhet av .NET. C#-syntax är inte så svårt att lära sig, särskilt inte om man kan Java, och har man flera års erfarenhet av att utveckla Java-baserade webblösningar borde det väl inte vara så svårt att få till något för .NET?

Så tycks man ha resonerat, men tyvärr är det ju inte riktigt så enkelt i verkligheten. Förutom en syntax måste man ha hyfsad koll på .NET Frameworks klassbibliotek och god kännedom om hur modellen för att utveckla webbapplikationer ser ut för ASP.NET; den skiljer sig en del från JSP och andra modeller. Men även om man läser in sig på dessa delar saknas en mycket viktig del, nämligen bästa praxis ("best practices"). Hur mycket man än vet om vad man kan göra med .NET, är det en annan fråga vad man bör göra.

För att fortsätta med exemplet med "Java-arkitekten"; i Java använder man get- och set-metoder för att kapsla in privata medlemmar. Exempel:

private int mAntal;

public int getAntal()
{
return mAntal;
}

public void setAntal(int varde)
{
mAntal = varde;
}

I .NET använder man isället egenskaper, "properties":

private int mAntal;

public int Antal
{
get { return mAntal; }
set { mAntal = value; }
}

Nu kan man lätt få för sig att det inte har någon betydelse vad man använder, utan att det mer är en fråga om tycke och smak, som till exempel när det gäller vilken rad man ska ha första måsvingen på. En del tror till och med (felaktigt) att get- och set-metoder är att föredra, även i .NET. Faktum är dock att det finns flera goda skäl till att properties är bästa praxis i .NET.

I .NET används i regel properties för att representera data, medan metoder används för att utföra handlingar på ett objekt. Genom att utrusta sin klass med en property signalerar man därför att det handlar om enkel dataåtkomst medan metodnamn med "Get" framför propertyns namn (t.ex. GetAntal i exemplet ovan) reserveras för att ge en fingervisning om att det då istället handlar om en relativt kostsam operation. Om man regelmässigt använder getters och setters förlorar man denna informativa distinktion.

Genom att namnet för både läsning och skrivning är detsamma för en property är det enkelt att använda reflection för properties. Det gör att många funktioner och verktyg har stöd för propertys, men inte för get- och set-metoder, till exempel databinding och designläget i Visual Studio som automatiskt visar properties på egentillverkade kontroller ("custom controls").

Sedan kan man förstås fråga sig varför man bör använda något annat än publika medlemsvariabler överhuvudtaget, oavsett om väljer properties eller get- och set-metoder. Till de främsta skälen hör, förutom vad som ovan nämnts, att man med properties (eller motsvarande) enkelt kan lägga till validering eller transformering utan att behöva ändra klassens interface. Eftersom man oftast inte kan vara helt säker på att detta inte kommer att behövas bör man alltid använda properties redan från början; att ändra en publik medlemsvariabel till en property i efterhand bryter nämligen binär kompatibilitet och innebär att du måste kompilera om beroende kod.

Det här är det första inlägget i vad som är tänkt att bli en serie om bästa praxis för programmering och design, särskilt på .NET-plattformen, som ni kommer att hitta under taggen "Bästa praxis" på denna blogg. Kom gärna med kommentarer, invändningar eller kompletteringar! (Använd kommentarsfunktionen.)

UPPDATERING: Jag använde tidigare getter/setter som benämning på get- och set-metoder, men det slog mig att även en property kan kallas getter/setter så jag använder nu konsekvent "get- och set-metoder".

UPPDATERING 2: Delar av ovanstående är baserat på riktlinjer från Framework Design Guidelines. En av kommentatorerna i boken, Rico Mariani, har många tänkvärda kommentarer utifrån ett prestandaperspektiv, så även gällande properties vs. public fields. Hans bloggpost om just detta är en bra påminnelse om att det ibland kan vara nödvändigt att frångå vad som i vanliga fall är bästa praxis. Även Eric Gunnersons kommentar i ämnet är läsvärd.

2 kommentarer:

Arne Evertsson sa...

Huruvida man använder get-metoder eller properties är en sak som man kvickt lär sig, och knappast något som påverkar en utvecklares produktivitet såsom java- eller .Net-utvecklare.

Den här typen av kodanalys kan och bör också automatiseras.

Joakim Sundén sa...

Ja, man kan tycka det, men ändå stöter man på tvivelaktigt användande av get- och set-metoder här och där; kanske därför att utvecklaren i fråga inte reflekterat över varför properties är att föredra.