Dela via


Välja mellan klass och struct

Kommentar

Det här innehållet skrivs om med behörighet från Pearson Education, Inc. från Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition. Den utgåvan publicerades 2008, och boken har sedan dess reviderats helt i den tredje utgåvan. En del av informationen på den här sidan kan vara inaktuell.

Ett av de grundläggande designbesluten som varje ramverksdesigner står inför är om en typ ska utformas som en klass (en referenstyp) eller som en struct (en värdetyp). Bra förståelse för skillnaderna i beteendet för referenstyper och värdetyper är avgörande för att göra det här valet.

Den första skillnaden mellan referenstyper och värdetyper som vi kommer att överväga är att referenstyper allokeras på heapen och skräpinsamlingen, medan värdetyper allokeras antingen på stacken eller infogade i innehållande typer och frigörs när stacken varvar ned eller när deras innehållande typ frigörs. Därför är allokeringar och frigöranden av värdetyper i allmänhet billigare än allokeringar och frigöranden av referenstyper.

Därefter allokeras matriser med referenstyper out-of-line, vilket innebär att matriselementen bara är referenser till instanser av referenstypen som finns på heapen. Värdetypmatriser allokeras infogade, vilket innebär att matriselementen är de faktiska instanserna av värdetypen. Därför är allokeringar och frigöringar av värdetypsmatriser mycket billigare än allokeringar och frigöranden av referenstypmatriser. Dessutom uppvisar värdetypsmatriser i de flesta fall mycket bättre referenslokalitet.

Nästa skillnad gäller minnesanvändning. Värdetyper boxas när de omvandlas till en referenstyp eller något av de gränssnitt som de implementerar. De kopplas från när de kastas tillbaka till värdetypen. Eftersom rutor är objekt som allokeras på heapen och är skräpinsamlade kan för mycket boxning och avboxning ha en negativ inverkan på heapen, skräpinsamlaren och i slutändan programmets prestanda. Däremot sker ingen sådan boxning eftersom referenstyper är gjutna. (Mer information finns i Boxning och unboxing).

Därefter kopierar referenstyptilldelningar referensen, medan tilldelningar av värdetyp kopierar hela värdet. Därför är tilldelningar av stora referenstyper billigare än tilldelningar av stora värdetyper.

Slutligen skickas referenstyper med referens, medan värdetyper skickas av värde. Ändringar i en instans av en referenstyp påverkar alla referenser som pekar på instansen. Värdetypsinstanser kopieras när de skickas av värde. När en instans av en värdetyp ändras påverkar den naturligtvis inte någon av dess kopior. Eftersom kopiorna inte skapas explicit av användaren, men skapas implicit när argument skickas eller returvärden returneras, kan värdetyper som kan ändras vara förvirrande för många användare. Därför bör värdetyper vara oföränderliga.

Som tumregel bör de flesta typer i ett ramverk vara klasser. Det finns dock vissa situationer där egenskaperna för en värdetyp gör det mer lämpligt att använda structs.

✔️ ÖVERVÄG att definiera en struct i stället för en klass om instanser av typen är små och ofta kortlivade eller ofta är inbäddade i andra objekt.

❌ UNDVIK att definiera en struct såvida inte typen har alla följande egenskaper:

  • Det representerar logiskt ett enda värde som liknar primitiva typer (int, doubleosv.).

  • Den har en instansstorlek under 16 byte.

  • Det är oföränderligt.

  • Den behöver inte boxas ofta.

I alla andra fall bör du definiera dina typer som klasser.

Portioner © 2005, 2009 Microsoft Corporation. Med ensamrätt.

Reprinted by permission of Pearson Education, Inc. from Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition by Krzysztof Cwalina and Brad Abrams, publicerad 22 okt 2008 av Addison-Wesley Professional som en del av Microsoft Windows Development Series.

Se även