Класс в .NET Framework аналогичен классу в C++: совокупность кода и данных, формирующая объект при создании экземпляра класса. В традиционных объектно-ориентированных языках, таких как C++, классы содержат члены-переменные и члены-функции. В среде .NET классы богаче, они могут содержать:
• поля (fields), аналогичные членам-переменным в C++;
• методы (methods), аналогичные членам-функциям в C++;
• свойства (properties), предоставляющие доступ к данным так же, как и поля, но реализованные с применением аксессоров (get и set);
• события (events), определяющие уведомления, которые способен распознавать класс.
Вот класс на языке С#, реализующий тип данных Rectangle:
class Rectangle
{
// Поля.
protected int width = 1;
protected int height = 1;
// Свойства,
public int Width
{
get { return width; }
set
{
if (value > 0)
width = value;
else
throw new ArgumentOutOfRangeException ("Width must be 1 or higher");
}
}
public int Height
<
get { return height; }
set
{
if (value > 0)
height = value;
else
throw new ArgumentOutOfRangeException ("Height must be 1 or higher");
}
}
public int Area
{
get { return width * height; }
// Методы (конструкторы}.
public Rectangle () {}
public Rectangle (int ex, int cy)
{
Width = ex;
Height = cy;
В классе Rectangle определено 7 членов: 2 поля, 3 свойства и 2 метода, причем оба являются конструкторами (так называются специальные методы, вызываемые каждый раз, когда создается экземпляр класса). Поля являются защищенными, т.е. доступ к ним имеют только сам класс Rectangle и его производные. Чтобы прочитать или записать ширину или высот)- прямоугольника, представленного объектом класса Rectangle, клиент должен задействовать свойства Width и Height. Обратите внимание на то, что аксессоры set этих свойств генерируют исключение, если указывается неверное значение. Такая защита была бы невозможна, если б высота и ширина объекта Rectangle задавались бы через открытые поля. Area является свойством, которое можно только читать, потому что у него нет аксессора set. При попытке установить значение свойства Area компилятор выдаст ошибку.
Во многих языках, ориентированных на .NET Framework, экземпляры классов создаются с помощью оператора new. Вот два оператора С#, создающие экземпляры Rectangle:
Rectangle rect = new Rectangle (); //Применен первый конструктор.
Rectangle rect = new Rectangle (3, 4); //Применен второй конструктор.
Созданный объект можно использовать, например, так:
rect.Width *= 2; // Удвоена ширина прямоугольника.
int area = rect.Area; // Получено новое значение его площади.
Важно отметить, что ни в С#, ни в каком-либо другом языке для .NET нет оператора delete. Вы создаете объекты, а уничтожает их сборщик мусора.
В С# классы определяют ссылочные типы (reference types), которые размещаются в кучах со сборкой мусора (часто их называют управляемыми кучами, так как ими управляет сборщик мусора). Доступ к ним происходит по ссылкам, которые по сути являются указателями. Кроме ссылочных типов существуют размерные типы (value types), которые вы изучите ниже. Обычно вам не придется учитывать различия между ними, но иногда разница важна: если не принимать ее во внимание, код может не работать. Подробней об этом см. ниже раздел «Упаковка и распаковка».
Все классы наследуют виртуальный метод Finalize класса System.Object — исходного корневого класса для всех типов данных. Метод Finalize вызывается прямо перед тем, как сборщик мусора уничтожит объект. Сборщик мусора освобождает занимаемую объектом память, но те классы, которые содержат описатели файлов, окон и другие неуправляемые ресурсы («неуправляемые» — потому что их не освобождает сборщик мусора), должны переопределять метод Finalize и с его помощью освобождать эти ресурсы. Это тоже имеет важные для разработчиков последствия. Об этом см. ниже раздел «Недетерминированное уничтожение».
Кстати, классы порождаются не более чем из одного исходного класса, но они могут быть производными от одного класса и любого количества интерфейсов.
При чтении документации по классам FCL не удивляйтесь, если подчас увидите длинный список базовых «классов». На самом деле это не классы, а интерфейсы. Кроме того, если при объявлении класса базовый класс не указан, то новый класс будет неявно порожден от System.Object. Следовательно, в любом классе можно вызывать метод ToString и другие методы System.Object.
Похожие статьи: