C# для профессионалов. Том II - Симон Робинсон
Шрифт:
Интервал:
Закладка:
Классы С#
До сих пор говорилось, что классы C# похожи на модули классов в VB. Мы уже видели одно различие, заключающееся в том, что классы C# допускают статические методы. Приведенный выше код метода Main() подчеркивает теперь еще одно различие: если делается что-то подобное в VB, то необходимо также задать для созданного объекта значение Nothing, когда работа с ним будет закончена. Однако ничего подобного не появляется в коде C#, так как в C# этого делать вовсе не нужно.
Причина этого различия состоит в том, что классы C# являются более эффективными и динамичными, чем их соответствующие аналоги в VB. Объекты классов VB являются на самом деле объектами COM, то есть каждый из них включает некоторый сложный код, который проверяет, сколько ссылок на объект поддерживается, поэтому каждый объект может разрушить себя, когда обнаружит, что он больше не нужен. В VB, если не задать объектную ссылку Nothing после завершения работы с объектом, это будет рассматриваться как плохая практика программирования, так как это означает, что объект не знает, что он больше не нужен, поэтому он может висеть в памяти возможно до окончания всего процесса.
Однако по соображениям производительности объекты C# не выполняют проверку такого рода. Вместо этого C# использует механизм, называемый сборкой мусора. При этом вместо того, чтобы каждый объект проверял, что он должен все еще существовать, среда выполнения .NET время от времени передает управление так называемому сборщику мусора. Сборщик мусора исследует состояние памяти, используя очень эффективный алгоритм для идентификации тех объектов, которые больше не нужны коду, и удаляя их. При наличии такого механизма неважно сбрасываются ли ссылки, когда работа с ними закончена, обычно достаточно просто подождать, пока переменная выйдет из области видимости.
Но если желательно задать ссылочную переменную, которая ни на что не указывает, то соответствующим ключевым словом C# является null, которое означает то же самое, что и Nothing в VB. Следовательно, там, где в VB было бы написано:
Set SomeDialog = Nothing;
в C# будет написано:
TheMainForm = null;
Заметим, что это само по себе делает не так уж много в C#, поскольку объект все равно не будет разрушен, пока не вызовется сборщик мусора.
Вход в цикл сообщений
Рассмотрим теперь конечную инструкцию в основном методе:
Application.Run(TheMainForm);
Эта инструкция запускает цикл сообщений. На самом деле здесь вызывается статический метод Run() класса System.Windows.Forms.Application. Этот метод обрабатывает цикл сообщений. Он переводит приложение (или, строго говоря, поток выполнения) в спящее состояние и просит Windows разбудить его, когда произойдет интересное событие. Метод Run() может получать один параметр, являющийся ссылкой на форму, которая будет обрабатывать все события. Run() заканчивается, когда произойдет и обработается событие, дающее указание форме завершить работу.
Когда метод Run() подходит к концу, то и метод Main() завершается. Так как этот метод был точкой входа в программу, то по его завершении выполнение всего процесса останавливается.
Один элемент синтаксиса в приведенных выше инструкциях, который может показаться удивительным, состоит в том, что при вызове метода Run() используются скобки, даже хотя никакое возвращаемое значение из этого метода не используется, и, следовательно, выполняется вызов, эквивалентный вызову подпрограммы в VB. VB в этом случае не требует скобок, но в C# существует правило, что при вызове метода всегда используются скобки.
При вызове любого метода в C# всегда используйте скобки, независимо от того, будет или нет использоваться возвращаемое значение.
Класс формы SquareRoot
Мы видели, как C# запускает цикл сообщений, но мы еще не изучили процесс вывода и создания самой формы. Мы также не определились с вопросом о вызове обработчиков событий. Упоминалось, что Windows вызывает такие обработчики событий, как метод OnClickButtonResults(). Но как Windows узнает, что нужно вызвать этот метод? Мы найдем ответы на все наши вопросы в определении класса SquareRootForm и в его базовом классе Form.
Отметим сначала, что класс SquareRootForm имеет достаточно много полей-членов. (Поле-член является выражением C# для переменной, которая определена как член класса. Можно представлять ее как переменную VB, которая имеет областью действия форму, или как переменную VB, которая определена в качестве члена модуля класса. Каждая такая переменная связана с определенным экземпляром класса — определенным объектом — и остается в области действия до тех пор, пока существует содержащий ее объект):
public class SquareRootForm : System.Windows.Forms.Form {
private System.Windows.Forms.TextBox txtNumber;
private System.Windows.Forms.TextBox txtSign;
private System.Windows.Forms.TextBox txtResult;
private System.Windows.Forms.Button cmdShowResults;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
Каждое из этих полей соответствует одному из элементов управления. Можно легко увидеть три текстовых поля и кнопку. Имеются также четыре метки, соответствующие областям текста на форме. Мы не будем ничего делать с этими метками, поэтому не стоит беспокоиться и давать им какие-то более понятные пользователю имена.
Однако каждая из этих переменных является просто ссылкой на объект, поэтому тот факт, что эти переменные существуют, не означает существования никаких экземпляров этих объектов — экземпляры объектов должны быть созданы отдельно. Процесс создания экземпляров этих элементов управления осуществляется с помощью так называемого конструктора. Конструктор в C# является примерным аналогом таким подпрограммам, как Form_Load(), Form_Initialize(), Class_Load() и Class_Initialize(). Это специальный метод, который автоматически вызывается, когда создается экземпляр класса, и он содержит код, необходимый для инициализации экземпляра.
Конструктор в классе легко опознать, так как он всегда имеет такое же имя, как и сам класс. В данном случае мы ищем метод с именем SquareRootForm:
public SquareRootForm() {
InitializeComponent();
}
Отметим, что так как это — конструктор, а не метод, который можно вызывать, он не определяет никакого возвращаемого типа. Однако после его имени стоят скобки, как и у метода. Можно использовать эти скобки для определения параметров, которые будут передаваться в конструктор (вспомните, что при создании переменной можно передавать параметры в скобках после предложения new). Определение конструктора указывает, нужны ли какие-то параметры для создания экземпляра объекта. Однако здесь нет никаких параметров. Мы увидим конструкторы, которые получают параметры, в примере Employee, рассматриваемом дальше в этом приложении.
В данном случае конструктор просто вызывает метод InitializeComponent(). Это в действительности связано с Visual Studio.NET. Visual Studio NET имеет все те же свойства, что и IDE VB6 для графических манипуляций элементами управления — щелчок мышью для размещения элементов управления на форме и т.д. Однако, так как теперь в C# определения всех элементов управления задаются в исходном коде, Visual Studio.NET должна иметь возможность прочитать исходный код, чтобы определить, какие элементы управления находятся на форме. Она делает это, разыскивая метод InitializeComponent() и определяя, экземпляры каких элементов управления там создаются.
InitializeComponent() является большим методом, поэтому он будет показан здесь полностью. Начинается он следующим образом:
private void InitializeComponent() {
this.txtNumber = new System.Windows.Forms.TextBox();
this.txtSign = new System.Windows.Forms.TextBox();
this.cmdShowResults = new System.Windows.Forms.Button();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.txtResult = new System.Windows.Forms.TextBox();
Показанный код является множеством вызовов для реального создания экземпляров всех элементов управления на форме. Этот фрагмент кода не содержит на самом деле ни одного нового элемента синтаксиса C#, который бы до сих пор не встречался. Следующая часть кода начинает задавать свойства элементов управления:
//
// txtNumber
//
this.txtNumber.Location = new System.Drawing.Point(160, 24);
this.txtNumber.Name = "txtNumber";
this.txtNumber.TabIndex = 0; this.txtNumber.Text = "";
//
// txtSign
//
this.txtSign.Enabled = false;
this.txtSign.Location = new System.Drawing.Point(160, 136);
this.txtSign.Name = "txtSign";