Classi statiche e membri di classi statiche (Guida per programmatori C#)

Una classe statica è sostanzialmente uguale a una classe non statica, ma con una differenza: non è possibile creare un'istanza di una classe statica. In altre parole, non è possibile usare l'operatore new per creare una variabile del tipo di classe. Poiché non esiste una variabile dell'istanza, è possibile accede ai membri di una classe statica usando il nome della classe stessa. Se ad esempio si dispone di una classe statica denominata UtilityClass che ha un metodo statico pubblico denominato MethodA, si chiama il metodo come illustrato nell'esempio seguente:

UtilityClass.MethodA();

Una classe statica può essere usata come un pratico contenitore per insiemi di metodi che funzionano solo sui parametri di input e non devono ottenere o impostare campi di istanza interni. Ad esempio, nella libreria di classi .NET la classe statica System.Math contiene diversi metodi che eseguono operazioni matematiche, senza alcun requisito per archiviare o recuperare dati univoci per una particolare istanza della classe Math. In altre parole, si applicano i membri della classe specificando il nome della classe e il nome del metodo, come illustrato nell'esempio seguente.

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

Come nel caso di tutti i tipi di classe, il runtime .NET carica le informazioni sul tipo di una classe statica quando viene caricato il programma che fa riferimento alla classe. Il programma non può specificare esattamente quando la classe viene caricata. Tuttavia, è garantito che la classe venga caricata, che i relativi campi vengano inizializzati e che il costruttore statico venga chiamato prima che il programma faccia riferimento per la prima volta alla classe. Un costruttore statico viene chiamato solo un volta e una classe statica rimane in memoria per la durata del dominio dell'applicazione in cui risiede il programma.

Nota

Per creare una classe non statica che consente la creazione di un'unica istanza di se stessa, vedere Implementing Singleton in C# (Implementare Singleton in C#).

Nell'esempio riportato di seguito sono indicate le principali funzionalità delle classi statiche:

  • Contiene solo membri statici.

  • Non è possibile creare un'istanza.

  • È sealed.

  • Non può contenere Costruttori di istanze.

La creazione di una classe statica è pertanto analoga alla creazione di una classe che contiene solo membri statici e un costruttore privato, che impedisce la creazione di istanze della classe. Una classe statica presenta un indubbio vantaggio. Consente infatti al compilatore di verificare che non vengano aggiunti accidentalmente membri di istanze Il compilatore garantisce che le istanze di questa classe non possano essere create.

Le classi statiche sono sealed e quindi non possono essere ereditate. Non possono ereditare da nessuna classe o interfaccia, ad eccezione di Object. Le classi statiche non possono contenere un costruttore di istanze. Tuttavia, possono contenere un costruttore statico. Le classi non statiche devono definire anche un costruttore statico se la classe contiene membri statici che richiedono un'inizializzazione più complessa. Per altre informazioni, vedere Costruttori statici.

Esempio

Ecco un esempio di classe statica che contiene due metodi di conversione della temperatura da Celsius a Fahrenheit e da Fahrenheit a 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.
 */

Membri statici

Una classe non statica può contenere metodi, campi, proprietà o eventi statici. È possibile chiamare il membro statico di una classe anche quando non esiste alcuna istanza della classe. Al membro statico si accede sempre tramite il nome della classe, non tramite il nome dell'istanza. Di un membro statico esiste una sola copia, indipendentemente dal numero di istanze della classe create. I metodi e le proprietà statiche non possono accedere ai campi non statici e agli eventi del relativo tipo di contenitore e non possono accedere a una variabile dell'istanza di qualsiasi oggetto, a meno che non venga esplicitamente passata come parametro del metodo.

È più frequente dichiarare una classe non statica con alcuni membri statici, piuttosto che dichiarare un'intera classe come statica. Due usi comuni dei campi statici sono quelli di tenere il conto del numero di oggetti di cui è stata creata un'istanza o di archiviare un valore che deve essere condiviso tra tutte le istanze.

I metodi statici possono essere sottoposti a overload ma non a override, perché appartengono alla classe e non a qualsiasi istanza della classe.

Sebbene non sia possibile dichiarare un campo come static const, il campo const è essenzialmente statico nel comportamento. Appartiene al tipo, non a istanze del tipo. Pertanto, è possibile accedere ai campi const utilizzando la stessa notazione ClassName.MemberName usata per i campi statici. Non è richiesta alcuna istanza dell'oggetto.

C# non supporta le variabili locali statiche (ovvero le variabili dichiarate nell'ambito del metodo).

I membri delle classi statiche vengono dichiarati tramite la parola chiave static prima del tipo restituito, come illustrato nell'esempio seguente:

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 non-static fields and properties...
}

I membri statici vengono inizializzati prima dell'accesso iniziale al membro statico e prima che venga chiamato il costruttore statico, se presente. Per accedere a un membro di una classe statica, usare il nome della classe anziché il nome di una variabile per specificare la posizione del membro, come illustrato nell'esempio seguente:

Automobile.Drive();
int i = Automobile.NumberOfWheels;

Se la classe contiene campi statici, fornire un costruttore statico che li inizializzi al caricamento della classe.

Una chiamata a un metodo statico genera un'istruzione di chiamata in Common Intermediate Language (CIL), mentre una chiamata a un metodo di istanza genera un'istruzione callvirt che controlla anche la presenza di riferimenti a oggetti nulli. Tuttavia, nella maggior parte dei casi la differenza di prestazioni tra i due non è significativa.

Specifiche del linguaggio C#

Per altre informazioni, vedere Classi statiche, Membri statici e di istanza e costruttori statici nella specifica del linguaggio C#. La specifica del linguaggio costituisce il riferimento ufficiale principale per la sintassi e l'uso di C#.

Vedi anche