Implementer private, statiske og indlejrede klasser
Forekomstkonstruktører bruges til at angive den kode, der udføres, når du opretter en ny forekomst af en klasse med operatoren new. Når forekomstkonstruktører bruger public adgangsændring, er det resulterende objekt tilgængeligt fra en hvilken som helst anden kode i dit program. Denne type adgang til et objekt og dets medlemmer er ofte ønskeligt, men der er tidspunkter, hvor du vil begrænse adgangen til en klasse eller til medlemmerne af en klasse.
Når du har brug for at skjule eller reducere eksponeringen af en klasse, kan du bruge adgangsmodifikatorer til at styre synligheden af klassen og dens medlemmer.
Access-modifikatorer
Alle typer og typemedlemmer har et tilgængelighedsniveau, der styrer, om de er tilgængelige fra anden kode i dit kompilerede program (eller andre assemblies).
Klasser, der er erklæret direkte i et navneområde, kan have public, internal eller file adgang. Klasser tildeles som standard internal adgang, når der ikke er angivet nogen adgangsændring.
Brug følgende adgangsmodifikatorer til at angive tilgængeligheden for en type eller et medlem, når du deklarerer den:
-
public: Kode i en hvilken som helst assembly kan få adgang til denne type eller dette medlem. Tilgængelighedsniveauet for den indeholdende type styrer tilgængelighedsniveauet for offentlige medlemmer af typen . -
private: Kun kode, der er erklæret i sammeclassellerstruct, kan få adgang til dette medlem. -
protected: Kun kode i sammeclasseller i en afledtclasskan få adgang til denne type eller dette medlem. -
internal: Kun kode i den samme assembly kan få adgang til denne type eller dette medlem. -
protected internal: Kun kode i den samme assembly eller i en afledt klasse i en anden assembly kan få adgang til denne type eller dette medlem. -
private protected: Kun kode i den samme assembly og i den samme klasse eller en afledt klasse kan få adgang til typen eller medlemmet. -
file: Kun kode i den samme fil kan få adgang til typen eller medlemmet.
Den record modifikator for en type medfører, at compileren syntetiserer ekstra medlemmer.
record-modifikatoren påvirker ikke standardtilgængeligheden for enten en record class eller en record struct.
Private class-konstruktører
En privat konstruktør er en konstruktør til særlige forekomster. Private konstruktører bruges ofte i klasser, der kun indeholder statiske medlemmer. Hvis en klasse har en eller flere private konstruktører og ingen offentlige konstruktører, kan andre klasser (undtagen indlejrede klasser) ikke oprette forekomster af klassen. For eksempel:
class NLog
{
// Private Constructor:
private NLog() { }
public static double e = Math.E; //2.71828...
}
Erklæringen af den tomme konstruktør forhindrer automatisk generering af en konstruktør uden parametre. Hvis du ikke angiver en adgangsændring for en konstruktør, privatesom standard . Den private modifikator skal dog bruges til at tydeliggøre, at klassen ikke kan instantieres.
Private konstruktører bruges til at forhindre oprettelse af forekomster af en klasse, når der ikke er nogen forekomstfelter eller -metoder, f.eks. klassen Math i .NET-biblioteket, eller når en metode kaldes for at hente en forekomst af en klasse. Hvis alle metoderne i klassen er statiske, kan du overveje at gøre den komplette klasse statisk.
I følgende eksempel vises en klasse, der bruger en privat konstruktør.
public class Counter
{
private Counter() { }
public static int currentCount;
public static int IncrementCount()
{
return ++currentCount;
}
}
class TestCounter
{
static void Main()
{
// If you uncomment the following statement, it generates
// an error because the constructor is inaccessible:
// Counter aCounter = new Counter(); // Error
Counter.currentCount = 100;
Counter.IncrementCount();
Console.WriteLine("New count: {0}", Counter.currentCount);
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output: New count: 101
Hvis du fjerner følgende sætning fra eksemplet, genererer compileren en buildfejl. Compileren forstår, at en privat konstruktør ikke er tilgængelig.
// Counter aCounter = new Counter(); // Error
Statiske klasser
En statisk klasse er stort set den samme som en ikke-statisk klasse med én vigtig forskel: En statisk klasse kan ikke instantieres. Med andre ord kan du ikke bruge operatoren new til at oprette en variabel ud fra en statisk klasse. Selvom du ikke kan oprette en forekomst af klassen, kan du få adgang til medlemmerne af en statisk klasse ved at referere til klassenavnet. Hvis du f.eks. har en statisk klasse med navnet UtilityClass, der har en offentlig statisk metode med navnet MethodA, kan du kalde metoden ved hjælp af en kombination af klasse- og metodenavnene. Denne syntaks vises i følgende eksempel:
UtilityClass.MethodA();
En statisk klasse kan bruges som en objektbeholder til metoder, der fungerer på inputparametre, og som ikke behøver at get eller set nogen interne forekomstfelter.
I .NET-klassebiblioteket indeholder den statiske System.Math-klasse f.eks. metoder, der udfører matematiske handlinger. Disse metoder fungerer uden krav om at gemme eller hente data, der er entydige for en bestemt forekomst af klassen Math. Du kalder medlemmerne af klassen ved at angive klassenavnet og metodenavnet som vist i følgende eksempel:
double dub = -3.14;
Console.WriteLine(Math.Abs(dub));
Console.WriteLine(Math.Floor(dub));
Console.WriteLine(Math.Round(Math.Abs(dub)));
// Output:
// 3.14
// -4
// 3
Som det er tilfældet med alle klassetyper, indlæser .NET-kørselstypeoplysningerne for en statisk klasse, når det program, der refererer til klassen, indlæses. Programmet kan ikke angive nøjagtigt, hvornår klassen indlæses. Det er dog garanteret at indlæse og få sine felter initialiseret, og dets statiske konstruktør kaldes, før der refereres til klassen for første gang i dit program. En statisk konstruktør kaldes kun én gang, og en statisk klasse forbliver i hukommelsen for levetiden for det programdomæne, hvor programmet er placeret.
Følgende liste indeholder hovedfunktionerne i en statisk klasse:
- Indeholder kun statiske medlemmer.
- Kan ikke instantieres.
- Er forseglet.
- Kan ikke indeholde forekomstkonstruktører.
Oprettelse af en statisk klasse er derfor stort set det samme som at oprette en klasse, der kun indeholder statiske medlemmer og en privat konstruktør. En privat konstruktør forhindrer, at klassen instantieres. Fordelen ved at bruge en statisk klasse er, at compileren kan kontrollere, at der ikke tilføjes nogen forekomstmedlemmer ved et uheld. Compileren garanterer, at forekomster af denne klasse ikke kan oprettes.
Statiske klasser er forseglet og kan derfor ikke nedarves. De kan ikke nedarve fra nogen klasse eller grænseflade undtagen Object. Statiske klasser kan ikke indeholde en forekomstkonstruktør. De kan dog indeholde en static konstruktør. Ikke-statiske klasser skal også definere en static konstruktør, hvis klassen indeholder static medlemmer, der kræver ikke-triviel initialisering.
Her er et eksempel på en statisk klasse, der indeholder to metoder, der konverterer temperaturen fra Celsius til Fahrenheit og fra Fahrenheit til Celsius:
public static class TemperatureConverter
{
public static double CelsiusToFahrenheit(string temperatureCelsius)
{
// Convert argument to double for calculations.
double celsius = Double.Parse(temperatureCelsius);
// Convert Celsius to Fahrenheit.
double fahrenheit = (celsius * 9 / 5) + 32;
return fahrenheit;
}
public static double FahrenheitToCelsius(string temperatureFahrenheit)
{
// Convert argument to double for calculations.
double fahrenheit = Double.Parse(temperatureFahrenheit);
// Convert Fahrenheit to Celsius.
double celsius = (fahrenheit - 32) * 5 / 9;
return celsius;
}
}
class TestTemperatureConverter
{
static void Main()
{
Console.WriteLine("Please select the convertor direction");
Console.WriteLine("1. From Celsius to Fahrenheit.");
Console.WriteLine("2. From Fahrenheit to Celsius.");
Console.Write(":");
string? selection = Console.ReadLine();
double F, C = 0;
switch (selection)
{
case "1":
Console.Write("Please enter the Celsius temperature: ");
F = TemperatureConverter.CelsiusToFahrenheit(Console.ReadLine() ?? "0");
Console.WriteLine("Temperature in Fahrenheit: {0:F2}", F);
break;
case "2":
Console.Write("Please enter the Fahrenheit temperature: ");
C = TemperatureConverter.FahrenheitToCelsius(Console.ReadLine() ?? "0");
Console.WriteLine("Temperature in Celsius: {0:F2}", C);
break;
default:
Console.WriteLine("Please select a convertor.");
break;
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Example Output:
Please select the convertor direction
1. From Celsius to Fahrenheit.
2. From Fahrenheit to Celsius.
:2
Please enter the Fahrenheit temperature: 20
Temperature in Celsius: -6.67
Press any key to exit.
*/
Statiske medlemmer
En ikke-statisk klasse kan indeholde statiske metoder, felter, egenskaber eller hændelser. Det statiske medlem kan kaldes på en klasse, selvom der ikke findes nogen forekomst af klassen. Det statiske medlem tilgås altid af klassenavnet og ikke navnet på forekomsten. Der findes kun én kopi af et statisk medlem, uanset hvor mange forekomster af klassen der oprettes. Statiske metoder og egenskaber kan ikke få adgang til ikke-statiske felter og hændelser i deres indeholdende type, og de kan ikke få adgang til en forekomstvariabel for et objekt, medmindre det udtrykkeligt overføres i en metodeparameter.
Det er mere typisk at deklarere en ikke-statisk klasse med nogle statiske medlemmer end at deklarere en hel klasse som statisk. To almindelige anvendelser af statiske felter er at bevare en optælling af antallet af objekter, der instantieres, eller til at gemme en værdi, der skal deles mellem alle forekomster.
Statiske metoder kan overbelastes, men ikke tilsidesættes, fordi de tilhører klassen og ikke til nogen forekomst af klassen.
Selvom et felt ikke kan erklæres som static const, er et const felt i bund og grund statisk i funktionsmåden. Den tilhører typen og ikke forekomster af typen . Du kan derfor få adgang til const felter ved hjælp af den samme ClassName.MemberName notation, der bruges til statiske felter. Der kræves ingen objektforekomst.
C# understøtter ikke statiske lokale variabler (dvs. variabler, der er erklæret i metodeområdet).
Du deklarerer statiske klassemedlemmer ved hjælp af nøgleordet static før medlemmets returtype, som vist i følgende eksempel:
public class Automobile
{
public static int NumberOfWheels = 4;
public static int SizeOfGasTank
{
get
{
return 15;
}
}
public static void Drive() { }
public static event EventType? RunOutOfGas;
// Other nonstatic fields and properties...
}
Statiske medlemmer initialiseres, før det statiske medlem tilgås første gang, og før den statiske konstruktør, hvis der er en, kaldes. Hvis du vil have adgang til et statisk klassemedlem, skal du bruge navnet på klassen i stedet for et variabelnavn til at angive medlemmets placering, som vist i følgende eksempel:
Automobile.Drive();
int i = Automobile.NumberOfWheels;
Hvis klassen indeholder statiske felter, skal du angive en statisk konstruktør, der initialiserer dem, når klassen indlæses.
Et kald til en statisk metode genererer en kaldinstruktion i CIL (Common Intermediate Language), mens et kald til en forekomstmetode genererer en callvirt instruktion, som også kontrollerer, om der er null-objektreferencer. Det meste af tiden er forskellen mellem ydeevnen mellem de to dog ikke signifikant.
Indlejrede klasser
En class type, der er defineret i en anden klasse, kaldes en indlejret klasse. For eksempel:
public class Container
{
class Nested
{
Nested() { }
}
}
Tilgængeligheden af en indlejret klasse er som standard private. Det betyder, at indlejrede klasser kun er tilgængelige fra deres indholdsklasse. I det forrige eksempel er klassen Nested utilgængelig for eksterne typer.
Du kan angive en adgangsændring for at definere tilgængeligheden af en indlejret type på følgende måde:
- Indlejrede typer af en klasse kan være
public,protected,internal,protected internal,privateellerprivate protected.
Men hvis du definerer en protected, protected internal eller private protected indlejrede klasse i en forseglet klasse, genereres compileradvarsel CS0628, "nyt beskyttet medlem erklæret i forseglet klasse".
Forsigtighed
Vær opmærksom på, at hvis du gør en indlejret type eksternt synlig, overtrædes kodekvalitetsreglen CA1034 "Indlejrede typer bør ikke være synlige".
Følgende eksempel gør klassen Nested offentlig:
public class Container
{
public class Nested
{
Nested() { }
}
}
Den indlejrede eller indre klasse kan få adgang til den indeholdende eller ydre klasse. Hvis du vil have adgang til den indeholdende klasse, skal du overføre den som et argument til konstruktøren af den indlejrede klasse. For eksempel:
public class Container
{
public class Nested
{
private Container? parent;
public Nested()
{
}
public Nested(Container parent)
{
this.parent = parent;
}
}
}
En indlejret klasse har adgang til alle de medlemmer, der er tilgængelige for dens indholdsklasse. Det kan få adgang til private og beskyttede medlemmer af den indeholdende klasse, herunder eventuelle nedarvede beskyttede medlemmer.
I den forrige erklæring er det fulde navn på klasse NestedContainer.Nested. Dette er det navn, der bruges til at oprette en ny forekomst af den indlejrede klasse på følgende måde:
Container.Nested nest = new Container.Nested();