Inhoud
Inleidingxiii
Voorwieisditboekbedoeld?xiv
Overdeinhoudxiv
Codeconventiesxv
Feedbackgevenxvi
Dankwoordxvi
Overdeauteurxvii
1Werkenmetgegevenstypen1
Advies1:Gebruikeigenschappeninplaatsvantoegankelijkedatamembers2
Advies2:Kiesimplicieteeigenschappenbovenvariabeledata8
Advies3:Kiesvoorconstantevalue-typen12
Advies4:Onderscheidmakentussenvalue-typenenreference-typen19
Advies5:Zorgervoordat0eengeldigestatusvoorvalue-typenis24
Advies6:Zorgervoordatdeeigenschappenzichgedragenzoalsgegevens29
Advies7:Beperkhetbereikvaneentypemettuples34
Advies8:Definieerlokalefunctiesopanoniemetypen40
Advies9:Begrijpderelatiestussendeveleverschillendebegrippenvan gelijkheid
46
Advies10:BegrijpdevalkuilenvanGetHashCode()54
2API-ontwerp63
Advies11:VermijdconversieoperatoreninuwAPI’s64
Advies12:Gebruikoptioneleparametersomoverloadingvan methodenteminimaliseren68
Advies13:Beperkdezichtbaarheidvanuwtypen72
Advies14:Geefdevoorkeuraanhetdefiniërenenimplementeren vaninterfacesbovenovererving76
Advies15:Begrijphoeinterfacemethodenverschillenvanvirtuelemethoden84
Advies16:Implementeerheteventmodelvoormeldingen89
ix
Advies17:Vermijdhetretournerenvanverwijzingennaar interneklassenobjecten95
Advies18:Kiesoverschrijvingenboveneventhandlers99
Advies19:Overloadgeenmethodendiezijngedefinieerdinbasisklassen102
Advies20:Begrijphoeeventsmeerruntimekoppelingen
tussenobjectengenereren106
Advies21:Declareeralleennonvirtualevents109
Advies22:Maakmethodegroependieduidelijk,minimaalenvolledigzijn115
Advies23:Geefdeelklassendeelmethodenvoorconstructors,mutatorsen eventhandlers122
Advies24:VermijdICloneableomdathetuwontwerpkeuzenbeperkt127
Advies25:Beperkarrayparameterstotparams-arrays132
Advies26:Schakeldirectefoutrapportageinbijiteratorsen asyncmethodenmetbehulpvanlokalefuncties136
3Taakgerichtasynchroonprogrammeren143
Advies27:Gebruikasync-methodenvoorasynchroonwerk144
Advies28:Schrijfnooitasyncvoid-methoden148
Advies29:Vermijdhetsamenstellenvansynchroneen
asynchronemethoden154
Advies30:Gebruikasync-methodenomthreadtoewijzingenen contextwisselingentevermijden158
Advies31:Vermijdhetonnodigordenenvancontext160
Advies32:AsynchroonwerksamenstellenmetTask-objecten164
Advies33:Overweegdeimplementatievanhettaakannuleringsprotocol170
Advies34:Cachegegeneraliseerdeasyncreturntypen177
4Parallelleverwerking181
Advies35:LeerhoePLINQparallellealgoritmenimplementeert182
Advies36:Construeerparallellealgoritmenmetexceptions inhetachterhoofd194
Advies37:Gebruikdethreadpoolinplaatsvanthreadstemaken200
Advies38:GebruikBackgroundWorkervoorcross-threadcommunicatie206
Advies39:Cross-threadaanroepeninXAML-omgevingenbegrijpen209
Advies40:Gebruiklock()alsuweerstekeuzevoorsynchronisatie218
Advies41:Gebruikhetkleinstmogelijkebereikvoorvergrendelhandles225
Advies42:Vermijdhetaanroepenvanonbekendecodein vergrendeldesecties229
Inhoud x
5Dynamischprogrammeren235
Advies43:Begrijpdevoor-ennadelenvandynamischtyperen236
Advies44:Gebruikdynamischtyperenomteprofiterenvanhet runtimetypevangenerictypeparameters245
Advies45:GebruikDynamicObjectofIDynamicMetaObjectProvider voorgegevensgestuurdedynamischetypen248
Advies46:BegrijphoeudeExpressionAPIgebruikt259
Advies47:MinimaliseerdynamischeobjecteninpublicAPI‘s266
6DeelnemenaandeC#-community273
Advies48:Zoekhetbesteantwoord,niethetpopulairsteantwoord274
Advies49:Neemdeelaanspecsencode276
Advies50:Overweegomwerkwijzenmetanalysersteautomatiseren277
Index281
xi Handboek– EffectieverprogrammereninC#
Inleiding
DeevolutieenveranderingvanC#blijftdoorgaan.Endaarmeeverandertook deC#-community.VoormeerontwikkelaarsisC#deeersteprofessioneleprogrammeertaal.Deledenvanonzecommunitywordennietgehinderddoorde vooropgezetteideeëndiegebruikelijkzijnonderdegenendieC#zijngaan gebruikennajarenervaringmetandereopCgebaseerdetalen.ZelfsdeontwikkelaarsdieC#aljarengebruikenvoelendenoodzaakomzichnieuwewerkwijzeneigentemakenalsgevolgvandesnelleopeenvolgingvanveranderingen.Sindsdecompileropensourceis,volgendeinnovatiesindeC#-taalelkaar snelop.DereviewvanvoorgesteldefunctionaliteitvoordeC#-taalgebeurtnu doordehelecommunityinplaatsvaneen kleinegroeptaalexperts.Decommunitykannuookdeelnemenaanhetontwerpenvandenieuwefunctionaliteit.
Wijzigingeninvoorgesteldearchitecturenentoepassingenveranderenookde taalidiomendiewijalsC#-ontwikkelaarsgebruiken.Hetbouwenvantoepassingendoorhetschrijvenvanmicroservices,distributedprogramma’sendescheidingvandataenalgoritmesmakenallemaaldeeluitvanmodernesoftwareontwikkeling.DeC#-taalheeftdeeerstestappengezetvoordeopnamevan dezeverschillendeidiomen.
Deorganisatievanhet HandboekeffectieverprogrammereninC# weerspiegelt zoweldewijzigingenindetaalalsdewijzigingenindeC#-community.Ditboek neemtunietmeeopeenhistorischereisdoordeveranderingenindetaal, maarbiedtuadviesoverhetgebruikvandehuidigeC#-taal.Deverschillende adviezenbehandelendenieuwetaal-enstructuureigenschappenendepraktijkendiedecommunityzichheefteigengemaaktdoorhetbouwenvanverschillendeversiesvansoftwareproductenmetC#.Dezevijftigadviezenvormeneen verzamelingaanbevelingendieualsprofessioneelontwikkelaarkuntgebruiken omC#meereffectiefintezetten.
DitboekgaatervanuitdatuC#7gebruikt,maarhetisgeenuitputtende behandelingvandenieuwetaalfuncties.Ditboekbiedtpraktischadvieshoeu dezefunctieskuntgebruikenvoorhetoplossenvanproblemenwaaruinde dagelijksepraktijktegenaankuntlopen.HetbehandeltinhetbijzonderdieC# 7-functionaliteitwaarmeeuopeennieuweenbeteremanierveelgebruikt idioomkuntschrijven.EenInternetzoekactietoontnogsteedsdeoplossingen diealjarenmeegaan.Ditboekbelichtdezeoudereoplossingenenlegtuit waaromdenieuwefunctionaliteitinC#betereoplossingenmogelijkmaakt.
VeelvandeaanbevelingeninditboekkuntucontrolerenmetopRoslyn-gebaseerdeanalysersencodefixes.Ikonderhoudeenrepositoryvandezebronnen
xiii
opditadres: https://github.com/BillWagner/MoreEffectiveCSharpAnalyzers
Wanneeruideeënhebtofwiltbijdragenaandezerepository,schrijfdaneen bijdrageofstuurmeeenverzoek.
Voorwieisditboekbedoeld?
Het HandboekeffectieverprogrammereninC# isgeschrevenvoorprofessioneleontwikkelaarsvoorwieC#deprimaire programmeertaalis.Ikgaervanuit datubekendbentmetdesyntaxiseneigenschappenvanC#endatuvaardigheidhebtinhetschrijvenvancodeinC#.Ditboekbevatgeenuitlegover standaardinstructiesentaaleigenschappen.Inplaatsdaarvanwordtbesproken hoeudefunctionaliteitvandehuidigeversievandeC#-taalkuntintegrerenin uwdagelijkseontwikkelwerk.
Daarnaastgaatditboekervanuitdatuenigekennishebtvande Common LanguageRuntime (CLR)ende just-in-time (JIT)compiler.
Overdeinhoud
Dataisalomtegenwoordigindehuidige wereld.Ineenobjectgeoriënteerde aanpakzijndataencodeonderdeelvaneentypemetdedaarbijbehorende bevoegdheden.Eenfunctioneleaanpakbehandeltmethodesalsdata.Eenservicegerichteaanpakscheidtdedatavandecodediededatabewerkt.DeevolutievanC#heeftervoorgezorgddatde taalfunctionaliteitbevatdiegemeenschappelijkisvooraldezeparadigma’s, hetgeencomplicatieskanopleverenbij uwontwerpkeuzes.Hoofdstuk1bespreektdezekeuzesenbiedteenleidraad bijhetkiezenvaneengeschikttaalidioomvoorverschillendetoepassingen.
ProgrammerenisinwezenhetontwerpvandeAPI.Hetbrengtuwverwachtingenoverhetgebruikvanuwcodeoveraandegebruikers.Hetspreektook boekdelenoveruwinzichtindebehoeftenenverwachtingenvanandereontwikkelaars.Inhoofdstuk2leertuhoeu hiervoorhetrijkepaletvanC#-taalfunctieshetbesteinzet.Uziethoeuluieevaluatiegebruikt,configureerbare interfacesmaaktenonduidelijkheidvoorkomttussendeverschillendetaalelementeninuwalgemeneinterfaces.
Taak-gebaseerdasynchroonprogrammerenlevertnieuweidiomenopvoorhet samenstellenvantoepassingenmetasynchronebouwstenen.Hetbeheersen vandezefunctionaliteitbetekentdatuAPI’skuntmakenvoorasynchrone takendieduidelijkweergevenwatdecodeuitvoert,endiemakkelijkzijnte gebruiken.Inhoofdstuk3leertuhoeu detaak-gebaseerdeasynchronetaalfunctionaliteitgebruiktvoorcodediewordtuitgevoerddoormeerdereservices endiedaarvoordiversebronnengebruikt.
Inleiding xiv
Hoofdstuk4neemteenspecifiekesubsetvanasynchroonprogrammerenonderdeloep: multithreadedparallelexecution.UziethoeumetPLINQdeverwerkingvancomplexealgoritmeseenvoudigerverdeeltovermeerderecores enmeerdereCPU’s.
Hoofdstuk5bespreekthetgebruikvanC# alseendynamische taal.InC#speelt hettypeeengroterol,metnamestatischetypen.Tegenwoordigbevateen toenemendaantalprogramma’szoweldynamischealsstatischetypen.MetC# kuntugebruikmakenvandynamische programmeertechniekenzonderde voordelenvanstatischetypenbinnenhetheleprogrammateverliezen.In hoofdstuk5leertuhoeudynamischefunctiesgebruiktenhoeuvoorkomtdat dynamischetypenhetheleprogrammabinnensluipen.
Hoofdstuk6sluitditboekafmetsuggestiesoverhoeukuntdeelnemenaande wereldwijdeC#-community.Erzijnveelmanierenwaaropukuntparticiperen enwaarmeeukunthelpenbijdeaanpassingvandeprogrammeertaaldieu dagelijksgebruikt.
Codeconventies
Hetweergevenvancodeineenboekbetekenthetsluitenvancompromissen watbetreftruimteenduidelijkheid.Ikhebgeprobeerdomdevoorbeeldente focussenophetspecifiekepuntdatdecodeillustreert.Vaakbetekentdathet weglatenvananderegedeeltenvaneenklasseofeenmethode.Somsbetekent ditookhetachterwegelatenvanerrorrecoverycodeomruimtetebesparen. Eenpublicmethodedientdeparametersenandereinvoertevalideren,maar ookdiecodewordthiermeestalweggelaten.Uitruimteoverwegingenisook devalidatievoorhetaanroepenvanmethodesen try/finally-constructies weggelaten,dezecontroleszijnvaakopgenomeniningewikkeldealgoritmen.
Ikveronderstelookdatdemeesteontwikkelaarsdetoepasselijkenamespace (naamruimte)kunnenvindenwanneereenvoorbeeldeenvandeveelgebruiktenamespacesgebruikt.Ukuntervanuitgaandatelkvoorbeeldimpliciet devolgende using-statementsbevat:
usingSystem; usingstaticSystem.Console; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Text;
xv Handboek– EffectieverprogrammereninC#
Feedbackgeven
Ondanksmijnbesteinspanningen–envandemensendiedeteksthebben nagekeken–ishetmogelijkdaterfoutenzijngeslopenindetekstofvoorbeelden.Alsudenktdatueenfouthebtgevonden,neemdancontactmetmijop viae-mail bill@thebillwagner.com ofviaTwitter @billwagner.Erratavindtu op http://thebillwagner.com/Resources/MoreEffectiveCS.Veelvandeadviezeninditboekzijngeïnspireerddoore-mail-enTwitter-gesprekkenmet andereC#-ontwikkelaars.Hebtuvragenofopmerkingenoverdeaanbevelingeninditboek,neemdancontactopmetmij.Discussiesvanalgemeen belangvindtuterugopmijnblogop http://thebillwagner.com/blog.
Dankwoord
Erzijnveelmensenaanwieikdankverschuldigdbenvoorhunbijdrageaandit boek.Ikhebhetvoorrechtomaldenodigejarendeeluittemakenvaneen verbazingwekkendeC#-community.Iedereenopde C#Insidersmailinglijst (binnenofbuitenMicrosoft)heeftbijgedragenmetideeënenconversaties,waardoorditeenbeterboekisgeworden.
IkmoeteenpaarledenvandeC#-communitypersoonlijkbedankenvoorde hulpmetideeën,enmethetomzettenvanideeëninconcreteaanbevelingen. DegesprekkenmetJonSkeet,DustinCampbell,KevinPilch,JaredParsons, ScottAllenenvooralMadsTorgersenzijndebasisvoorveelnieuweideeënin dezeuitgave.
Voordezeuitgavehadikdebeschikking overeengeweldigteamvantechnischerecensenten.JasonBock,MarkMichaelisenEricLippertbestudeerdende tekstenvoorbeeldenenverbeterdenzeerdekwaliteitvanhetboekdatunuin handenhebt.Hunrecensieswarengrondigencompleet,enmeerdandatkan niemandvragen.Daarnaastkwamenzemetaanbevelingendiemehielpenom veelvandeonderwerpenbeteruitteleggen.
HetteamvanAddison-Wesleyiseendroomommeetewerken.Trina MacDonaldiseenfantastischeredacteur,leermeesterendedrijvendekracht diehetwerkgedaankrijgt.ZesteuntopMarkRenfrowenOliviaBasegio,net alsik.Hunbijdragengarandeerdendat hetvoltooidemanuscripteenkwalitatiefhoogstandjewas,vancovertotcoverenallesdaartussenin.CurtJohnson blijftopmarketingtechnischgebiedfantastischwerkleveren.Hetmaaktniet uitwelkmediumuhebtgekozen,Curtheeftdehandgehadinhetbestaanvan ditboek.
IkvindheteeneeromdeeluittemakenvanScottMeyers’sserieboeken.Hij bekijktelkmanuscriptenbiedtsuggestiesenopmerkingenvoorverbetering. Scottisongelooflijkgrondigenzijnervaringinsoftware,hoewelnietinC#,
Inleiding xvi
betekentdathijallegebiedenvindtwaarikietsnietduidelijkgenoeghebuitgelegdofwaareenadviesgoedopzijn plaatszouzijn.Zijnfeedback,zoals altijd,isvanonschatbarewaardegeweestindevoorbereidingvandezeuitgave.
Zoalsaltijdheeftmijnfamiliemijdetijdgegevenzodatikditmanuscriptkon voltooien.MijnvrouwMarlenewachtte geduldigtallozeuren,terwijlikweggingomteschrijvenofvoorbeeldentemaken.Zonderhaarsteunzouikdit boeknooithebbenafgekregen,enhetzouooknietzobevredigendzijn geweestomdezeprojectentevoltooien.
Overdeauteur
BillWagner iseenvan’swereldsbelangrijksteC#-ontwikkelaarsenhijislid vandeECMAC#StandardsCommittee.HijisvoorzittervandeHumanitarian Toolbox,isbenoemdtotMicrosoftRegionalDirectoreniselfjaar.NETMVP,en hijtradonlangstoetotde.NETFoundationAdvisoryCouncil.Billheeft samengewerktmetbedrijven,variërendvanstarterstotgroteondernemingen, aanhetverbeterenvanhunsoftwareontwikkelingsprocesenhetuitbreiden vanhunsoftwareontwikkelingsteams.HijwerktmomenteelmetMicrosoftaan het.NETCorecontentteam.Hijcreëertleermiddelenvoorontwikkelaarsdie geïnteresseerdzijnindeC#-taalen.NETCore.BillbehaaldeeenBSinComputerScienceaandeUniversiteitvanIllinoisinChampaign-Urbana.
xvii Handboek– EffectieverprogrammereninC#
Werkenmet gegevenstypen
C#werdoorspronkelijkontworpenvoorsoftwareontwikkelingmetobjectgeoriënteerdetechnieken,waarindegegevensendefunctionaliteitwordensamengebracht.Naverloopvantijdzijnernieuweidiomentoegevoegdterondersteuning vansteedsvakervoorkomendeprogrammeertechnieken.Eenvan dietrendsishetscheidenvandegegevensopslagvandemethodendiedezegegevensbewerken.Dezetendenswordtgedreven doordeovergangnaargedistribueerdesystemen,waarineen applicatiewordtverdeeldinkleinereprocessen,dieelkéénfunctieofenkeleverwantefunctiesuitvoeren.Deintroductievaneen nieuwestrategievoorhetscheidenvangegevensenmethode resulteertnatuurlijkookindeontwikkelingvannieuweprogrammeertechnieken.Enzoleidennieuweprogrammeertechnieken weertotnieuwetaalfuncties.
Indithoofdstukleertutechniekenomdatatescheidenvande methodendiedezegegevensmanipulerenofverwerken.Deze gegevenszijnnietaltijdobjecten;somszijnhetfunctiesenpassievedatacontainers.
1
Advies1:Gebruikeigenschappeninplaatsvan
toegankelijkedatamembers
Eigenschappen(properties)zijnaltijdeenonderdeelgeweestvandeC#-taal, maarsindsdeeerstereleasevanC#zijnverschillendeuitbreidingengeïntroduceerdwaardoordeeigenschappennogkrachtigerzijn.Ukuntbijvoorbeeldverschillendetoegangsbeperkingenopgevenvoordegetterensetter.Gebruiktu Auto-Property,danhoeftuniethandmatigtypentedeclarerenvoordeeigenschappen(inplaatsvandatamembers)en kuntuautomatischaccessmodifiers toekennen,zoalsRead-Only.Expression-bodieddatamembersbiedeneennog beknopteresyntaxis.Alsunogsteedsveldenalspublicdeclareertbijuwdatatypen,stopdaardanmee.SchrijftunogsteedsGet-enSet-methodenmetde hand,houderdanmeeop.Meteigenschappenmaaktudatamemberseenvoudigbeschikbaaralsonderdeelvande publicinterface,terwijlutochdeverwachteinkapselingbehoudtvaneenobjectgeoriënteerdeomgeving.Eigenschappenzijntaalelementendietoegankelijkzijnalsofzedatamemberszijn, maarzewordengeïmplementeerdalsmethoden.
Sommigemembersvaneentypewordenhetbestweergegevenalsdata:de naamvaneenklant,de(x, y)-coördinatenvaneenpuntofdeomzetvanvorig jaar.Meteigenschappenkuntueeninterfacemakendiewerktalsofdeze rechtstreekstoegangheefttotdedatavelden,maardienogsteedsallevoordelenbiedtvaneenmethode.Clientcode benaderteigenschappenalsofdeze publicveldenbenadert.Defeitelijkeimplementatiegebruiktechtermethoden, waarinuhetgedragvandeeigenschappen-accessorsdefinieert.
Het.NETFrameworkgaatervanuitdatueigenschappengebruiktvooruw publicdatamembers.Sterkernog,deklassenvoorgegevensbindinginhet .NETFrameworkondersteuneneigenschappen,geenpublicdatafields.Dit geldtvoorallebibliothekenvoorgegevensbinding:WPF,WindowsFormsen WebForms.Gegevensbindingkoppelteeneigenschapvaneenobjectaaneen besturingselementvandegebruikersinterface.Hierbijwordt reflection gebruikt omdegenoemdeeigenschaptevindenineentype:
textBoxCity.DataBindings.Add(“Text”, address,nameof(City));
DezecodekoppeltdeeigenschapTextvanhetbesturingselementtextBoxCity aandeeigenschapCityvanhetobjectaddress.Ditwerktnietmeteenpublic datafieldmetdenaamCity;deontwerpersvandeFrameworkClassLibrary hebbenhiervoorgeenondersteuningingebouwd.Hetgebruikvanpublicdata memberswordtinobjectorientedprogramming(OOP)gezienalseenslechte
Hoofdstuk1 –Werkenmetgegevenstypen 2
publicclassCustomer {
werkwijze,zodatondersteuninghiervoornietisopgenomenindeFramework ClassLibrary.DezeomissieiseenredentemeeromdejuisteOOP-technieken tevolgen.
Gegevensbindingisalleenvantoepassingopklassenmetelementendiewordenweergegevendoordecodevanuwgebruikersinterface(UI).Maardat betekentnietdatueigenschappenuitsluitendmoetgebruikenindeUI-code: gebruikookeigenschappenvoorandereklassenenstructuren.Eigenschappen zijnveeleenvoudigertewijzigenwanneerulaterdeeisenofhetgedragwilt aanpassen.SteldatubesluitdathettypeKlantnooiteenlegenaammaghebben.AlsudeeigenschapvoorhetveldNaamalspublichebtingesteld,danis dezenieuweeiseenvoudigtoetevoegen,omdatditslechtsopéénplaats hoefttegebeuren:
privatestringname; publicstringName
get=>name; set
if(string.IsNullOrWhitespace(value)) thrownewArgumentException( “Namecannotbeblank”, nameof(Name)); name=value; }
//Moreelided } }
Haduhiervoorpublicdatamembersgebruikt,danhadudegehelecodemoetendoorlopenenaanpassenopiederelocatiewaardenaamvandeklant wordttoegewezen.Datkostmeertijd,veelmeertijd.
Omdateigenschappenwordengeïmplementeerdmetmethoden,ishettoevoegenvanondersteuningvoormultithreadingeenvoudiger.Ubreidtde implementatievandeget-enset-accessorsuitmetgesynchroniseerdetoegang totdedata(zieadvies39voormeerinformatie):
publicclassCustomer {
privateobjectsyncHandle=newobject();
{
{
3 Handboek– EffectieverprogrammereninC#
privatestringname;
publicstringName { get { lock(syncHandle) returnname; } set { if(string.IsNullOrEmpty(value)) thrownewArgumentException( “Namecannotbeblank”, nameof(Name)); lock(syncHandle) name=value; }
//Moreelided
publicclassCustomer
Eigenschappenhebbendezelfdetaalfunctiesalsmethoden.Eneigenschappen kunnenookvirtueelzijn:
publicvirtualstringName
get; set; }
Merkopdatdelaatstepaarvoorbeeldendeimplicieteeigenschapsyntaxis gebruiken.Hetisgebruikelijkommeteeneigenschapeenbackingstoreopte zetten.Meestalhoeftugeencodevoorvalideringtoetevoegenaandeaccessorsvandeeigenschap.DeC#-taalondersteuntdevereenvoudigdeimpliciete syntaxisvaneigenschappenzodatveelvandeceremoniëlecodeachterwege kanblijvenwaarmeeeeneenvoudigveldzichtbaarisalseigenschap.Decompilercreëerteenprivateveld(meestaleen backingstore genoemd)enimplementeertdebenodigdelogicavoorzoweldeget-alsdeset-accessor.
Ukunteigenschappenookalsabstractdefiniëreneneigenschappendefiniëren alsonderdeelvaneeninterfacedefinitie.Hiervoorgebruiktuvergelijkbaresyn-
}
}
{
{
}
Hoofdstuk1 –Werkenmetgegevenstypen 4
taxisalsbijimplicieteeigenschappen.Inhetvolgendevoorbeeldzietueen eigenschapsdefinitieineengeneriekeinterface.Hoeweldesyntaxisconsistent ismetimplicieteeigenschappen,bevatdezeinterfacedefinitiegeenenkele implementatie.Hetdefinieerteencontractwaaraanelktypemoetvoldoendat dezeinterfaceimplementeert.
publicinterfaceINameValuePair<T>
stringName{get;}
TValue{get;set;}
Eigenschappenzijnvolwaardige,eersteklastaalelementendieeenuitbreiding zijnvanmethodendieinternegegevensbenaderenofwijzigen.Alleswatu kuntdoenmetmember-functies,kuntudoenmeteigenschappen.Methet gebruikvaneigenschappenvermijdtuookeenanderebelangrijkebronvan foutendiemetveldenmogelijkis:ukuntgeeneigenschapaaneenmethode doorgevenmethetkeyword ref of out.
Deaccessorsvooreeneigenschapzijntweeverschillendemethodendiebinnenhettypezijngecompileerd.UkuntinC#bijeeneigenschapverschillende accessmodifiersopgevenvoordeget-enset-accessors.Dezeflexibiliteitgeeft unogmeercontroleoverdezichtbaarheidvandegegevenselementendieu meteigenschappeninstelt:
publicclassCustomer
publicvirtualstringName { get; protectedset; }
//Remainingimplementationomitted }
Desyntaxisvandeeigenschapreiktverderdaneenvoudigegegevensvelden. Alsuwtypegeïndexeerdeitemsbevatalsonderdeelvandeinterface,dankunt uindexeerdersgebruiken.Indexeerderszijnhiergeparametriseerdeeigenschappen.Dezewerkwijzeiseenhandigemanieromeeneigenschaptemaken diedeitemsineenreeksretourneert:
publicintthis[intindex]
{
}
{
{ 5 Handboek– EffectieverprogrammereninC#
get=>theValues[index]; set=>theValues[index]=value; }
privateint[]theValues=newint[100];
//Accessinganindexer: intval=someObject[i];
Indexeerdershebbendezelfdetaalondersteuningalsdeeigenschappenvan eenenkelitem:zewordengeïmplementeerdalsmethodendieuschrijft,zodat uelkeverificatieofberekeningbinnendeindexeerfunctiekunttoepassen.Een indexeerderkanvirtueelofabstractzijn,ukuntzedeclarerenininterfaces,en zekunnenread-onlyofread-writezijn.Eendimensionaleindexeerdersmet numeriekeparameterszijntoegankelijkvoorgegevensbinding.Andere indexeerdersmetniet-integereparameterskuntugebruikenomkaartente definiëren:
publicAddressthis[stringname]
{
get=>addressValues[name];
set=>addressValues[name]=value;
privateDictionary<string,Address>addressValues;
InovereenstemmingmetdemultidimensionalearraysinC#,kuntumultidimensionaleindexeerdersmakenmetovereenkomstigeofverschillende typenopelkeas:
publicintthis[intx,inty]
=>ComputeValue(x,y);
publicintthis[intx,stringname]
=>ComputeValue(x,name);
Merkopdatalleindexeerderszijngedeclareerdmethetkeyword this.Ukunt eenindexeerderinC#geennaamgeven,dusheeftelkeaparteindexeerderin eentypeeenduidelijkeparameterlijst nodigomonduidelijkheidtevoorkomen. Bijnaallemogelijkhedenvaneigenschappenzijnookbeschikbaarvoor indexeerders:indexeerderskunnenvirtueelofabstractzijn;zijkunnenafzonderlijkeaccessmodifiershebbenvoor settersengetters.Erisechteréénverschil:ukuntgeenimplicieteindexeerdersmaken,ietswatwelkanmeteigenschappen.
}
Hoofdstuk1 –Werkenmetgegevenstypen 6
Dezefunctionaliteitvaneigenschappenisprimaenhetiseenfijneverbetering tenopzichtevaneerdereversiesvanC#.Maarwellichtbentunogsteeds geneigdomeeneersteimplementatiemetdatamemberstemakenen–zodra udevoordelendaarvannodighebt–dedatamemberstevervangendoor eigenschappen.Datklinktalseenredelijkestrategie,maarhetisverkeerd.
Bekijkhetvolgendegedeelte vaneenklassendefinitie:
//Usingpublicdatamembers,badpractice: publicclassCustomer { publicstringName;
//Remainingimplementationomitted }
Dezeklassendefinitiebeschrijfteenklantmeteennaam.Ukuntdenaam opvragenofinstellenmetdegebruikelijkenotatie:
string name=customerOne.Name; customerOne.Name=“ThisCompany,Inc.”;
Datiseenvoudigenrechttoerechtaan.U kuntzichvoorstellendatulaterhet datamemberNamekuntkuntvervangendooreeneigenschap,endatdecode ongewijzigdzoublijvenwerken.Datisminofmeerwaar.Eigenschappenzijn bedoeldomopdatamemberstelijkenalszewordenbenaderd,datisimmers hetdoelvandesyntaxis.Maareigenschappenzijn geen gegevens;detoegang toteeneigenschapgenereertandereMSIL-instructies(MicrosoftIntermediate Language)dandetoegangtotgegevens.
Hoeweleigenschappenendatamemberscompatibelzijnindebroncode,zijn zenietbinaircompatibel.Inhetvoor dehandliggendegevalbetekentdezebeperkingdatwanneeruvaneenpublicdatamemberoverschakeltnaardeequivalentepubliceigenschap,ualleco dediegebruikmaaktvanhetpublicdata member,opnieuwmoetcompileren.C#behandeltbinairesamenstellingenals eersteklasburgers.Eéndoelvandetaalisdathetmogelijkisoméénenkelebijgewerkteassemblagevrijtegevenzonderdevolledigetoepassingteupdaten. Hetveranderenvaneendatamemberineeneigenschapverbreektdebinaire compatibiliteit,endaarmeewordthetupgradenvaneenenkeleassemblage veelmoeilijker.
AlsudeMSIL-instructies vooreeneigenschapbekijkt,zouuzichkunnenafvragenwatderelatieveperformanceisvaneigenschappenendatamembers.De prestatiesmeteigenschappenzullennietsnellerzijndanmetdatamembers, maarwaarschijnlijkooknietlangzamer.De just-in-time(JIT)compilerverwerkt
7 Handboek– EffectieverprogrammereninC#
inlinebepaaldemethodeaanroepen,inclusiefdievanpropertyaccessors.Als deJIT-compilerinlinedepropertyaccessorsafhandelt,danzijndeprestaties vandatamemberseneigenschappenhetzelfde.Zelfswanneereenproperty accessornietinlinewordtafgehandeld,danishetverschilinprestatiesdeverwaarloosbaretijdvaneenfunctieaanroep.Ditverschilisalleenineenklein aantalsituatiesmeetbaar.
Eigenschappenzijnmethodendiezichtbaarzijnvanuitdeaanroependecode zoalsgegevens,ietswatwaarschijnlijkbijuwgebruikerseenaantalverwachtingenwekt.Zijziendetoegangtoteeneigenschapalsofhetdetoegangtot datais.Immers,zozietheteruit.Uwpropertyaccessorsmoetendezeverwachtingenwaarmaken.Get-accessorszoudengeenwaarneembarebijwerkingenmoetenhebben.Daarentegenwijzigenset-accessorsdestatus,en gebruikerszoudendezeveranderingenmoetenkunnenzien.
Propertyaccessorswekkendusookprestatieverwachtingenbijuwgebruikers. Eenpropertyaccesszieteruitalseendatafieldaccess.Erzoudengeensignificantandereprestatiekarakteristiekenmogenzijntenopzichtevaneeneenvoudigedataaccess.Propertyaccessorsdienengeenlangdurigeberekeningenuit tevoerenofaanroepentussenapplicatiestemaken(zoalshetuitvoerenvan databasequery’s)ofanderelangdurigebewerkingenuitvoerendienietconsistentzijnmetwatuwgebruikersverwachtenvaneenpropertyaccessor.
Gebruikeigenschappenwanneerugegevensbeschikbaarmaaktindepublicof protectedinterfacesvaneentype.Gebruikeenindexeerdervoorreeksenof dictionary’s.Declareeralledatamemberszonderuitzonderingalsprivate.Deze instellingenbiedenonmiddellijkondersteuningvoorgegevensbinding,waardooruindetoekomstveeleenvoudigerdeimplementatievandemethoden kuntaanpassen.Hetextrawerkdatnodigisomeenvariabeleineeneigenschapintekapselen,bedraagtéénoftweeminutenvanuwdag.Tervergelijking,wiltuachterafeigenschappengebruikenenervoorzorgendatuw programma’scorrectblijvenwerken,danbrengtdatveleurenwerkmetzich mee.Wanneerunueenbeetjetijdinvesteert,danbespaartuzichzelflater veeltijd.
Advies2:Kiesimplicieteeigenschappen bovenvariabeledata
UitbreidingenaandesyntaxisvaneigenschappeninC#latenuuwontwerpdoel meteigenschappenduidelijkmaken.DemoderneC#-syntaxismaakthetmogelijkdatuachterafookuwontwerpkuntwijzigen.Beginmeteigenschappenen maakveeltoekomstigescenario’smogelijk.
Hoofdstuk1 –Werkenmetgegevenstypen 8
Wanneerubenaderbaregegevensaaneenklassetoevoegt,zijndeeigenschapsaccessorsvaaksimpeleomslagen(wrappers)vooruwgegevensvelden. Alsdathetgevalis,danverhoogtudeleesbaarheidvanuwcodedoorimplicieteeigenschappentegebruiken:
publicstringName{get;set;}
Decompilermaakthetbackingfieldmeteendoordecompilergegenereerde naam.Metdesettervandeeigenschapkuntudewaardevanhetbackingfield wijzigen.Omdatdecompilerdenaamvanhetbackingfieldgenereert,moetu ookbinnendeeigenklassedeeigenschapsaccessoraanroepenomhetbacking fieldtewijzigen.Datisgeenprobleem:hetaanroepenvandeeigenschapsaccessordoethetwerk,enomdatdegegenereerdeeigenschapsaccessoreen enkeltoewijzingsstatementis,wordthetwaarschijnlijkinlineuitgevoerd.Het runtimegedragvandeimplicieteeigenschapishetzelfdealshetruntimegedrag bijhetbenaderenvanhetbackingfield,ookwatbetreftperformance.
Implicieteeigenschappenondersteunendezelfdeaccessmodifiersalshun explicietetegenhangers.Ukuntzelfde gewensterestrictiestoevoegenaande setaccessor:
publicstringName { get; protectedset; }
//Or publicstringName { get; internalset; }
//Or publicstringName { get; protectedinternalset; }
//Or publicstringName { get; privateset; }
9 Handboek– EffectieverprogrammereninC#
//Canbesetonlyintheconstructor: publicstringName{get;}
Implicieteeigenschappengenererendezelfdecodevooreeneigenschapmet backingfieldalsdieuzelfineeneerdereversievanC#handmatigzouhebben geschreven.Gebruiktuimplicieteeigenschappen,danwordtuproductieveren uwklassenzijnbeterleesbaar.Dedeclaratievaneenimplicieteeigenschap toontaaniedereendieuwcodeleestprecieswatuwiltmaken.Deextrainformatiekanachterwegeblijven,zodathetbestandoverzichtelijkblijft.
Aangezienimplicieteeigenschappendezelfdecodegenererenalsexpliciete eigenschappen,kuntuimplicieteeigenschappengebruikenomvirtueleeigenschappentedefiniëren,virtueleeigenschappenteoverschrijven(override)of eeneigenschapteimplementerendieisgedefinieerdineeninterface.
Wanneeruimplicieteenvirtueleeigenschapmaakt,hebbenafgeleideklassen geentoegangtotdedoordecompilergegenereerdebackingstore.Echter, overschrijvingen(overrides)hebbenweltoegangtotdeaccessmethodes get en set vandebasiseigenschappen,netals metelkeanderevirtuelemethode:
publicclassBaseType
publicvirtualstringName
get; protectedset;
publicclassDerivedType:BaseType
publicoverridestringName
get=>base.Name; protectedset { if(!string.IsNullOrEmpty(value)) base.Name=value;
//Or
{
}
{
}
{
{
} } } Hoofdstuk1 –Werkenmetgegevenstypen 10
//Originalversion publicclassPerson
Uhebttweeextravoordelenwanneeruimplicieteeigenschappengebruikt. Teneerste:wanneerulaterdeimplicieteeigenschapwiltvervangendooreen concreteimplementatievoorgegevensvalidatieofandereacties,danmaaktu binair-compatibelewijzigingenbinnendeklasse.Tentweede:devalidatiekomt slechtsopéénlocatieterecht.
IneerdereversiesvanC#benaderden demeesteontwikkelaarshetbacking fieldrechtstreeksomhetbinnendeeigenklassetewijzigen.Diewerkwijze produceertcodediedevalidatieenfoutcontroleverspreidtdoorhetgehele bestand.Elkewijziginginhetbackingfieldvaneenimplicieteeigenschaproept de(eventueelprivate)eigenschapsaccessoraan.Veranderdaaromdeimplicieteeigenschapsaccessorineenexplicieteeigenschapsaccessorenschrijfdan allecodevoordevalidatieindenieuweaccessor:
publicstringFirstName{get;set;} publicstringLastName{get;set;} publicoverridestringToString()=>
$"{FirstName}{LastName}“;
//Laterupdatedforvalidation publicclassPerson
publicPerson(stringfirstName,stringlastName)
//Leveragevalidationinpropertysetters: this.FirstName=firstName; this.LastName=lastName;
privatestringfirstName; publicstringFirstName
get=>firstName; set {
if(string.IsNullOrEmpty(value)) thrownewArgumentException( “Firstnamecannotbenullorempty”); firstName=value;
{
}
{
{
}
{
} } 11 Handboek– EffectieverprogrammereninC#
privatestringlastName; publicstringLastName { get=>lastName; privateset
{ if(string.IsNullOrEmpty(value)) thrownewArgumentException( “Lastnamecannotbenullorempty”); lastName=value;
publicoverridestringToString()=> $"{FirstName}{LastName}“;
Wanneeruimplicieteeigenschappengebruikt,dankomtallevalidatieopéén plaatsterecht.Alsudeaccessorkuntblijvengebruikeninplaatsvanhetbackingfieldrechtstreekstebenaderen,dan blijftalleveldvalidatieopéénlocatie.
Implicieteeigenschappenhebbenéénbelangrijkebeperking:uzenietgebruikenoptypenmethetattribuut Serializable.Debestandsindelingvoorpersistenteopslagisafhankelijkvandeveldnaamvandedoordecompilergegenereerdebackingstore.Erisgeengarantiedatdieveldnaamhetzelfdeblijft, datwilzeggen,dienaamkanveranderentelkenswanneerudeklasseaanpast.
Ondankshunbeperkingenbesparenimplicieteeigenschappenontwikkelingstijd,zeproducerenleesbarecode,enzebevordereneenstijlvanontwikkeling waarinallevalidatievoorveldwijzigingenopéénlocatiegebeurt.Alsuwcode overzichtelijkeris,danishetonderhoudvandiecodeookeenvoudiger.
Advies3:Kiesvoorconstantevalue-typen
Constanten(immutabletypes)zijneenvoudigtebegrijpen:nadatzezijn gemaakt,houdenzeeenconstantewaarde.Alsudeparametersvalideert waarmeeuhetobjectconstrueert,dankuntuerzekervanzijndathetobject vanafdatpunteengeldigestatusheeftenhoudt;ukuntimmersdeinterne statusvanhetobjectnietmeerwijzigen.Daarmeekanookdefoutcontrole achterwegeblijvenomdatergeenstatuswijzigingenmeermogelijkzijnnadat hetobjectisgebouwd.Deconstantetypenzijninherentveiligtegebruikenin threads:meerderelezerskunnendezelfdeinhoudbenaderen.Alsdeinterne statusnietkanveranderen,ishetonmogelijkdatverschillendethreadsincon-
}
}
}
Hoofdstuk1 –Werkenmetgegevenstypen 12
sistenteweergavenvandegegevenszien.Constantetypenkuntuveiligexporterenvanuituwobjecten,omdatdeaanroeperdeinternestatusvanuwobjectennietkanwijzigen.
Constantetypenwerkenbeterinverzamelingenmethashcode.Dewaardedie wordtgeretourneerddoor Object.GetHashCode() moeteenconstante instantiezijn(zieadvies10);datisaltijdhetgevalvoorconstantetypen.
Indepraktijkishetheelmoeilijkomelktypeconstanttemaken.Daaromisdit adviesvantoepassingopzowelatomaire alsconstantevalue-typen.Ontbindt uwtypeninstructurendieopnatuurlijke wijzeeenenkeleentiteitvormen.Het typeAdresvormteenzo’nentiteit.Eenadresiséénitemdatbestaatuitverschillendegerelateerdevelden,eneenwijziginginéénveldbetekentwaarschijnlijkookwijzigingeninanderevelden.HettypeKlantisdaarentegengeen atomairtype.Eenklanttypebevatwaarschijnlijkveelgegevens,zoalseen adres,eennaameneenofmeertelefoonnummers,enelkvandezeonafhankelijkegegevenskanwordengewijzigd.Zokaneenklantvantelefoonnummer veranderenzonderteverhuizen.Alseen klantverhuist,kandezewelhetzelfde telefoonnummerbehouden.Eneenklantkanzijnofhaarnaamwijzigenmet behoudvantelefoonnummerenzondervanadresteveranderen.Eenklantobjectisnietatomair;hetissamengestelduitveelverschillendeconstante typen–eenadres,eennaam,ofeenverzamelingvantelefoonnummeren meer.Atomairetypenzijnenkeleentiteiten:bijeenwijzigingishetlogischom degeheleinhoudtevervangen.Deuitzonderinghieropiswanneerueenvan desamenstellendeveldenwijzigt.
Hieriseentypischeimplementatievaneenvariabel(mutable)adres:
//MutableAddressstructure publicstructAddress {
privatestringstate; privateintzipCode;
//Relyonthedefaultsystem-generated
//constructor publicstringLine1{get;set;} publicstringLine2{get;set;} publicstringCity{get;set;} publicstringState
get=>state; set
{
13 Handboek– EffectieverprogrammereninC#
ValidateState(value); state=value; }
publicintZipCode { get=>zipCode; set {
ValidateZip(value); zipCode=value; }
//Otherdetailsomitted }
//Exampleusage:
Addressa1=newAddress(); a1.Line1=“111S.Main”; a1.City=“Anytown”; a1.State=“IL”; a1.ZipCode=61111;
//Modify: a1.City=“AnnArbor”;//Zip,Stateinvalidnow a1.ZipCode=48103;//Statestillinvalidnow a1.State=“MI”;//Nowfine
Internestatusveranderingenbetekenendathetmogelijkisomdeonveranderlijkheidvanhetobjectteschenden,althanstijdelijk.NadatuhetveldCityhebt gewijzigd,krijgthetobjecta1eenongeldigestatus.Deplaatsisveranderden komtnietmeerovereenmetdeinhoudvandeveldenStateenZipCode.De codezieteronschuldiggenoeguit,maar steldatditfragmentonderdeelisvan eenmultithreadedprogramma:elkewijzigingindecontextnadewijzigingin CityenvoordeaanpassingvanStateofZipCodekanleidentoteeninconsistenteweergavevandegegevensineenanderethread.
Zelfsalsugeenmultithreadedprogrammaschrijft,dankuntutochindeproblemenkomenbijveranderingvandeinternestatus.Steldatdeinhoudvan hetveldZipCodeongeldigis,zodatseteenexceptiongenereert.Uhebtnog nietallewijzigingenaangebracht, maarnuheefthetsysteemeenongeldige status.Omditprobleemteverhelpen,moetuaanzienlijkehoeveelheidinterne
{
}
}
Hoofdstuk1 –Werkenmetgegevenstypen 14
valideringscodetoevoegenaandeadresstructuur.Dievalideringscodeverhoogtopzijnbeurtdeomvangendecomplexiteitvanuwtotalecode.Alsu volledigebeveiligingvoorexceptionswiltimplementeren,danzouubeveiligingscodemoetenschrijvenvoorelkcodeblokwaarinumeerdanéénveldverandert.Threadsafetyvereisthettoevoegenvansignificantethreadsynchronisatiecontrolesvoorelkeeigenschapsaccessor,zowelsetalsget.Almetalisdat veelwerk–endatwordtwaarschijnlijkmeerwanneerulaternieuwefuncties toevoegt.
Alsuhetadresobjectnodighebtals struct,daniseenbetereaanpakomhet constantof immutable temaken.Maakeerstalleinstantieveldenread-only voorexterngebruik.
publicstructAddress
//Remainingdetailselided publicstringLine1{get;} publicstringLine2{get;} publicstringCity{get;} publicstringState{get;} publicintZipCode{get;}
publicAddress(stringline1, stringline2, stringcity, stringstate, intzipCode): this()
Line1=line1; Line2=line2; City=city; ValidateState(state); State=state; ValidateZip(zipCode); ZipCode=zipCode;
Nuhebtueenconstanttype,gebaseerdopdepublicinterface.Schrijfnualle benodigdeconstructorsvoordeinitialiseringvan Address-structuur.Deze structuurheeftslechtséénextraconstructornodig,waarbijelkveldwordt opgegeven.Eenkopieerconstructorisnietnodigomdatdetoewijzingsoperator netzoefficiëntis.Onthouddatdestandaardconstructornogsteedstoeganke-
{
{
} }
15 Handboek– EffectieverprogrammereninC#
lijkis.Eriseenstandaardadreswaarallestringsdewaardenullhebbenende zipcodedewaarde0.
publicAddress(stringline1, stringline2, stringcity, stringstate, intzipCode): this() {
Line1=line1; Line2=line2; City=city; ValidateState(state); State=state; ValidateZip(zipCode); ZipCode=zipCode;
//Createanaddress:
Hetgebruikvanhetconstantetypevereisteenietsandereaanroepvoorhet wijzigenvanzijnstatus.Umaaktnamelijkeennieuwobjectinplaatsvanhet bestaandeexemplaaraantepassen:
Addressa2=newAddress(“111S.Main”, “”,“Anytown”,“IL”,61111);
//Tochange,re-initialize: a2=newAddress(a1.Line1, a1.Line,“AnnArbor”,“MI”,48103);
Dewaardevana1vindtuopeenvantweelocaties:Anytownopdeoriginele locatieofAnnArboropdebijgewerktelocatie.Uwijzigtniethetbestaande adres,daarmeegenereertudeongeldigetijdelijkestatuszoalsinhetvorige voorbeeld.Detussentijdselocatiesbestaanslechtstijdensdeuitvoeringvande adresconstructorenzijnnietzichtbaar buitendieconstructor.Zodraeennieuw adresobjectisgemaakt,wordtdewaardeervanvooraltijdvastgelegd.Deze codeisook exceptionsafe:a1heeftofweldeoorspronkelijkewaardeofde nieuwewaarde.Alstijdensdebouwvanhetnieuweadresobjecteenexception wordtgegenereerd,isdeoorspronkelijkewaardevana1ongewijzigd.
Alsueenconstanttypecreëert,moetuervoorzorgendatuwcodegeengaten heeftdiecliëntentoestaanomdeinternestatusteveranderen.Value-typen biedengeenondersteuningvoorafgeleidetypen,dusuhoeftgeenbeveiliging
}
Hoofdstuk1 –Werkenmetgegevenstypen 16
intebouwenvoorafgeleidetypendieveldenwijzigen.Echter,ineenconstant typemoetuweloppassenmetelkvelddatverwijstnaareenvariabelreference-type.Wanneeruconstructorsvoordezetypenimplementeert,moetu eenbeveiligingskopievandatvariabeletypemaken.Indevolgendevoorbeeldenwordtervanuitgegaandat Phone eenconstantvalue-typeis,omdatwe onshieralleenbezighoudenmetconstantevalue-typen:
//Almostimmutable:Thereareholesthatwould
//allowstatechanges.
publicstructPhoneList
privatereadonlyPhone[]phones;
publicPhoneList(Phone[]ph)
phones=ph;
publicIEnumerable<Phone>Phones { get{returnphones;}
Phone[]phones=newPhone[10];
//Initializephones
PhoneListpl=newPhoneList(phones);
//Modifythephonelist:
//alsomodifiestheinternalsofthe(supposedly)
//immutableobject. phones[5]=Phone.GeneratePhoneNumber();
Dearrayklasseiseenreference-type.Inditvoorbeeldverwijstdearraybinnen de struct PhoneListnaardezelfdegeheugenlocatievandearrayPhonesdieis toegewezenbuitenhetobject.Datwilzeggendatontwikkelaarsnuuwconstantestructuurkunnenwijzigenmeteen anderevariabeledienaardezelfde opslaglocatieverwijst.Uelimineertdezemogelijkheidmeteenveiligheidskopie vandearray. Array iseenvariabeltype,dusdeklasse ImmutableArray vande namespace System.Collections.Immutable zoueenalternatiefkunnenzijn. Hetvorigevoorbeeldtoontdevalkuilenvaneenvariabeleverzameling.Alshet type Phone eenvariabelreference-typeis,zijnernogmeermogelijkheden voorellende.Eenclientkandandewaardenvandeverzamelingwijzigen,zelfs
{
{
}
} }
17 Handboek– EffectieverprogrammereninC#
lsdeverzamelingisbeveiligdtegenwijziging.Ditprobleemiseenvoudigte verhelpenalsuhettype ImmutableList gebruikt:
publicstructPhoneList
privatereadonlyImmutableList<Phone>phones;
publicPhoneList(Phone[]ph)
phones=ph.ToImmutableList();
publicIEnumerable<Phone>Phones=>phones;
Erzijndriestrategieëndieukuntgebruiken.Decomplexiteitvanhettype bepaaltwelkevandedrieuhetbestekunt gebruikenvoorhetinitialiserenvan uwconstantetype.Teneerste,ukuntéénconstructordefiniërenwaarmee clientseenobjectkunneninitialiseren.Neembijvoorbeelddeadresstructuur waarbijeenconstructorisgedefinieerdwaarmeeclientseenadreskunneninitialiseren.Hetopzettenvandebenodigdeconstructeursisvaakdeeenvoudigsteaanpak.
Tentweede,ukuntfactorymethodenmakenomdestructuurteinitialiseren. Factory’smakenhetmakkelijkeromgemeenschappelijkewaardentecreëren. Het.NETFrameworktype Color gebruiktdezestrategieomsysteemkleurente initialiseren.Destatischemethoden Color.FromKnownColor() en Color. FromName() retournereneenkopievaneen kleurwaardediedehuidige waardevooreenbepaaldesysteemkleurvertegenwoordigt.
Tenderde,ukunteenvariabelecompanionklassemakenwanneermeerstapsoperatiesnodigzijnvoordevolledige constructievaneenconstanttype.De stringklassevan.NETgebruiktdezestrategiemetdeklasse System.Text. StringBuilder.Metdeklasse StringBuilder vultueenstringinopeenvolgendestappen.Nadatallebewerkingendienodigzijnomdestringtebouwen klaarzijn,haaltudeconstantestringopin StringBuilder
Deconstantetypenzijneenvoudigerteschrijvenengemakkelijkerteonderhouden.Schrijfnietblindelingsget-enset-accessorsvoorelkeeigenschapvan eentype.ImplementeerInplaatsdaarvan,wanneereentypegegevens opslaat,dezedanalsconstante,atomairevalue-typen.Ubouwtmetdezeentiteiteneenvoudigingewikkeldestructuren.
{
{
}
}
Hoofdstuk1 –Werkenmetgegevenstypen 18