Статические классы и члены статических классов (Руководство по программированию в C#)

Статический класс в основном совпадает с нестатичным классом, но существует одно отличие: статический класс не может быть создан. Другими словами, нельзя использовать новый оператор для создания переменной типа класса. Так как переменная экземпляра отсутствует, вы обращаетесь к членам статического класса с помощью самого имени класса. Например, если есть статический класс, называемый UtilityClass, имеющий открытый статический метод с именем MethodA, вызов метода выполняется, как показано в следующем примере:

UtilityClass.MethodA();

Статический класс можно использовать в качестве удобного контейнера для наборов методов, которые просто работают с входными параметрами и не должны получать или задавать поля внутреннего экземпляра. Например, в библиотеке классов .NET статический класс System.Math содержит методы, выполняющие математические операции, без требования сохранять или извлекать данные, уникальные для конкретного экземпляра класса Math. Это значит, что члены класса применяются путем задания имени класса и имени метода, как показано в следующем примере.

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

Как и в случае со всеми типами классов, среда выполнения .NET загружает сведения о типе статического класса при загрузке программы, ссылающейся на класс. Программа не может точно указать, когда загружается класс. Однако он гарантированно загружает и инициализирует поля и вызывается статическим конструктором до того, как класс ссылается впервые в вашей программе. Статический конструктор вызывается только один раз, и статический класс остается в памяти на время существования домена приложения, в котором находится программа.

Примечание.

Создание нестатического класса, который допускает создание только одного экземпляра самого себя, см. в документе Реализация Singleton в C#.

Ниже приведены основные возможности статического класса.

  • Содержит только статические члены.

  • Невозможно создать экземпляр.

  • Является запечатанным.

  • Не удается содержать конструкторы экземпляров.

По сути, создание статического класса аналогично созданию класса, содержащего только статические члены и закрытый конструктор. Закрытый конструктор не допускает создания экземпляров класса. Преимущество применения статических классов заключается в том, что компилятор может проверить отсутствие случайно добавленных членов экземпляров. Компилятор гарантирует, что экземпляры этого класса не могут быть созданы.

Статические классы запечатаны и поэтому не могут быть унаследованы. Они не могут наследоваться от любого класса или интерфейса, кроме Object. Статические классы не могут содержать конструктор экземпляра. Однако они могут содержать статический конструктор. Нестатические классы также должен определять статический конструктор, если класс содержит статические члены, для которых нужна нетривиальная инициализация. Дополнительные сведения см. в разделе Статические конструкторы.

Пример

Ниже приведен пример статического класса, который содержит два метода, которые преобразуют температуру из Цельсия в Fahrenheit и из Fahrenheit в Цельсию:

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.
 */

Статические члены

Нестатический класс может содержать статические методы, поля, свойства или события. Статический член вызывается в классе, даже если экземпляр класса не существует. Доступ к статическому члены всегда выполняется по имени класса, а не экземпляра. Существует только одна копия статического члена, независимо от того, сколько создано экземпляров класса. Статические методы и свойства не могут получить доступ к нестатическому полям и событиям в их содержательном типе, и они не могут получить доступ к переменной экземпляра любого объекта, если он не передается явным образом в параметре метода.

Обычно объявлять нестатический класс с некоторыми статическими элементами, чем объявлять весь класс как статический. Два распространенных использования статических полей — сохранить количество объектов, созданных экземплярами, или сохранить значение, которое должно быть общим для всех экземпляров.

Статические методы могут быть перегружены, но не переопределены, поскольку они относятся к классу, а не к экземпляру класса.

Хотя поле не может быть объявлено как static const, константное поле по сути статично в его поведении. Он относится к типу, а не к экземплярам типа. Таким образом, к полям можно получить доступ с помощью той же ClassName.MemberName нотации, const используемой для статических полей. Экземпляр объекта не требуется.

C# не поддерживает статические локальные переменные (то есть переменные, объявленные в методе область).

Для объявления статических методов класса используется ключевое слово static перед возвращаемым типом члена, как показано в следующем примере:

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...
}

Статические члены инициализированы перед первым доступом к статическому элементу и до вызова статического конструктора. Для доступа к члену статического класса следует использовать имя класса, а не имя переменной, указывая расположение члена, как показано в следующем примере:

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

Если класс содержит статические поля, должен быть указан статический конструктор, который инициализирует эти поля при загрузке класса.

Вызов статического метода создает инструкцию вызова в общем промежуточном языке (CIL), а вызов метода экземпляра создает callvirt инструкцию, которая также проверка для ссылок на объекты NULL. Однако большую часть времени разница между этими двумя производительностью не является значительной.

Спецификация языка C#

Дополнительные сведения см. в разделе "Статические классы", "Статические" и "элементы экземпляра" и "Статические конструкторы" в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

См. также