Классы

Обновлен: Ноябрь 2007

C# является объектно-ориентированным языком программирования и аналогично другим современным языкам группирует связанные поля, методы, свойства и события в структуры данных, которые называются классами.

Классы и объекты

Класс, по сути, является чертежом для пользовательского типа данных. Определив класс, его можно использовать, загрузив в память. Класс, загруженный в память, называется объектом или экземпляром. Экземпляр класса создается с помощью ключевого слова C# new.

Далее представлен пример определения класса с именем SampleClass и создание объекта с именем sampleClass1, который является экземпляром этого класса. Поскольку необходимо, чтобы функция Main была определена внутри класса, в следующем коде также определяется класс Program, однако он не используется для создания объекта.

using System;

class SampleClass
{
    public void SayHello()
    {
        Console.WriteLine("Hello, World!");
    }
}

class Program
{
    //Main is the entrypoint, where every C# program starts
    static void Main(string[] args)
    {
        SampleClass sampleClass1 = new SampleClass();  // Create an object
        sampleClass1.SayHello();                       // Call a method
    }
}

Подобно тому, как на основе одного чертежа можно построить несколько зданий, можно создать любое количество объектов одного класса. Очень часто используются массивы или списки, содержащие множество объектов одного класса. Каждый экземпляр класса занимает отдельную область памяти; значения его полей (исключая статические поля, как описано далее) также являются независимыми. В представленном ниже примере кода создается один объект типа Animal, ему задается размер "2", и другой объект с размером "3". Однако для этого правила существует важное исключение, а именно статический член.

Члены экземпляра и статические члены

Статический член представляет собой метод или поле, доступ к которым можно получить без ссылки на определенный экземпляр класса. Самым общим статическим методом является Main, который представляет точку входа для всех программ C#; следует обратить внимание, что создавать экземпляр содержащего класса для вызова метода Main не нужно. Еще одним часто используемым статическим методом является WriteLine в классе Console. При доступе к статическим методам необходимо обратить внимание на отличие в синтаксисе; с левой стороны оператора dot вместо имени экземпляра используется имя класса: Console.WriteLine.

Поле класса, объявляемое как статическое, будет общим для всех экземпляров класса. Если size в следующем примере кода были объявлены как статические и один объект Animal изменил значение, значение будет изменено для всех объектов типа Animal.

В статическом классе все элементы также статические. Использование статических классов, методов и полей целесообразно в ряде случаев для повышения производительности и эффективности. Однако если предполагается, что поле является полем экземпляра, хотя на самом деле оно статическое, могут возникнуть неявные ошибки. Дополнительные сведения см. в разделе Статические классы и члены статических классов (руководство по программированию в C#).

Классы и файлы

Каждая программа C# имеет, по крайней мере, один класс. При разработке программы рекомендуется (но не требуется) хранить отдельный класс в каждом файле исходного кода (файле CS). Если для создания классов используется интегрированная среда разработки C#, она в это же время автоматически сгенерирует файл исходного кода.

Инкапсуляция

Обычно класс представляет характеристики объекта и выполняемые им действия. Например, чтобы представить животное как класс C#, необходимо задать ему размер, скорость и силу, представленными в виде чисел, а также некоторые функции, например MoveLeft(), MoveRight(), SpeedUp(), Stop() и так далее, в которых можно написать код для выполнения "животным" этих действий. В C# класс животного может выглядеть следующим образом.

    public class Animal
    {
        private int size;
        private float speed;
        private int strength;

        public void MoveLeft()  // method
        {
            // code goes here...
        }

        // other methods go here...
    }

При просмотре .NET Framework Class Library будет ясно, что каждый класс представляет "объект", например XmlDocument, String, Form, и для каждого такого "объекта" существуют различные действия, который он может выполнить (методы), характеристики, которые можно прочитать и изменить (свойства) и уведомления (события), отправляемые при выполнении некоторых заданных действий. Методы, свойства и события, а также все остальные внутренние переменные и константы (поля) называются членами класса.

Группировка членов в классы имеет не только логический смысл, она также позволяет скрывать данные и функции, которые должны быть недоступны для другого кода. Этот принцип называют инкапсуляцией. При просмотре библиотек классов платформы .NET Framework будут видны только открытые члены этих классов. Возможно, каждый класс имеет закрытые члены, используемые внутренне этим классом или связанными классами, которые не предназначены для использования приложениями. Создавая собственные классы, нужно решить, какие члены будут открытыми, а какие — закрытыми.

Наследование

Класс может наследовать от другого класса, что означает, что он включает все члены — открытые и закрытые — исходного класса, а также дополнительные определяемые им члены. Исходный класс называется базовым классом, а новый класс — производным классом. Производный класс создается для представления особых возможностей базового класса. Например, можно определить класс Cat, который наследует от Animal. Cat может выполнять все то же, что и Animal и дополнительно одно уникальное действие. Код C# выглядит следующим образом.

    public class Cat : Animal
    {
        public void Purr()
        {
        }
    }

Нотация Cat : Animal означает, что Cat наследует от Animal и что Cat также имеет метод MoveLeft и три закрытые переменные: size, speed и strength. Если определяется класс SiameseCat, который наследует от Cat, он будет содержать все члены Cat, а также все члены Animal.

Полиморфизм

В сфере компьютерного программирования полиморфизмом называют возможность производного класса изменять или переопределять методы, которые он наследует от базового класса. Эта функция используется, если в методе, который имеет отличия либо не определен в базовом классе, нужно выполнить какие-то особые действия. Например, поскольку метод Animal.MoveLeft должен быть общим, чтобы подходить для всех животных, он является, возможно, очень простым, как например "изменение положения так, чтобы голова животного была в направлении X". Однако для класса Cat этого может быть недостаточно. Может потребоваться указать, как Cat двигает лапами и хвостом при поворотах. И если класс Fish или класс Bird уже определен, возможно, потребуется переопределить метод MoveLeft разными способами для каждого из классов. Поскольку можно настроить поведение метода MoveLeft для конкретного класса, в коде, создающем класс и вызывающем его методы, отсутствует отдельный метод для каждого животного. Пока объект наследует от Amimal, вызывающий код может вызывать лишь метод MoveLeft и собственную версию метода объекта.

Конструкторы

В каждом классе существует конструктор — метод с тем же именем, что и у класса. Конструктор вызывается при создании объекта на базе определения класса. Обычно конструкторы задают начальные значения переменных, определенных в классе. Конструкторы не используются, если начальным значением для числовых типов данных буде ноль, "false" для логических типов данных или null для ссылочных типов, поскольку эти типы данных инициализируются автоматически.

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

class SampleClass
{
    string greeting;

    public SampleClass()
    {
        greeting = "Hello, World";
    }

    public SampleClass(string message)
    {
        greeting = message;
    }

    public void SayHello()
    {
        System.Console.WriteLine(greeting);
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Use default constructor.
        SampleClass sampleClass1 = new SampleClass();
        sampleClass1.SayHello();

        // Use constructor that takes a string parameter.
        SampleClass sampleClass2 = new SampleClass("Hello, Mars");
        sampleClass2.SayHello();
    }
}

Перегрузка операторов

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

Деструкторы

Если вы работали с C++, то, возможно, вы уже располагаете сведениями о деструкторах. В связи с наличием в C# системы автоматического сбора мусора маловероятно, что вам когда-либо придется применять деструктор, если только класс не использует неуправляемые ресурсы. Дополнительные сведения см. в разделе Деструкторы (руководство по программированию в C#).

Структуры

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

См. также

Задачи

Практическое руководство. Вызов метода в объекте

Практическое руководство. Наследование от класса

Основные понятия

Основы языка C#

Ссылки

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

класс (Справочник по C#)

struct (справочник по C#)