Пошаговое руководство. Создание компонента с помощью Visual C#
Обновлен: Ноябрь 2007
Компоненты хранят код, доступный для многократного использования, в форме объектов. Приложение, использующее код компонента (создавая объекты и вызывая их свойства и методы), называется клиентом. Клиент не обязательно должен находиться в той же сборке, что и используемый им компонент.
Следующие процедуры построены на основе друг друга, поэтому важно выполнять их именно в том порядке, в котором они приведены.
Примечание. |
---|
Отображаемые диалоговые окна и команды меню могут отличаться от описанных в справке в зависимости от текущих параметров или версии среды. Для изменения настроек выберите Параметры импорта и экспорта в меню Сервис. Дополнительные сведения см. в разделе Параметры Visual Studio. |
Создание проекта
Чтобы создать библиотеку классов CDemoLib и компонент CDemo
В меню Файл выберите Создать и щелкните пункт Проект, чтобы открыть диалоговое окно Создание проекта. Из списка типов проектов Visual C# выберите шаблон проекта Библиотека классов и введите CDemoLib в поле Имя.
Примечание. Для создаваемого проекта следует всегда задавать имя. Это гарантирует, что будет задано корневое пространство имен, имя сборки и имя проекта, а компонент, создаваемый по умолчанию, будет помещен в правильное пространство имен.
В Обозревателе решений щелкните правой кнопкой мыши CDemoLib и выберите в контекстном меню Свойства. Обратите внимание, что в поле Пространство имен по умолчанию появляется элемент CDemoLib.
Для определения имен компонентов в сборке используется корневое пространство имен. Например, если в двух сборках содержатся компоненты с именем CDemo, то можно указать свой компонент CDemo, используя имя CDemoLib.CDemo.
Закройте диалоговое окно.
В меню Проект выберите Добавить компонент.
В диалоговом окне Добавление нового элемента выберите Класс компонента и введите CDemo.cs в поле Имя. Щелкните Добавить для создания компонента.
В результате в библиотеку классов добавляется компонент CDemo.
В Обозревателе решений щелкните правой кнопкой мыши CDemo.cs и выберите из контекстного меню Просмотреть код. Открывается редактор кода.
Обратите внимание на : Component непосредственно сразу после public partial class CDemo. В этом разделе задается класс, от которого наследует создаваемый класс. По умолчанию компонент является наследником класса Component, предоставляемого системой. Класс Component предоставляет компоненту различные возможности, в частности способность использовать конструкторы.
В Обозревателе решений щелкните правой кнопкой мыши Class1.cs и выберите Удалить. В результате класс, предоставляемый библиотекой классов и используемый по умолчанию, удаляется (он не будет использоваться в этом пошаговом руководстве).
Из меню Файл выберите команду Сохранить все, чтобы сохранить проект.
Добавление конструкторов и деструкторов
Конструкторы управляют инициализацией компонента, а метод Finalize — его удалением. Код конструктора и метода Finalize класса CDemo поддерживает определение числа существующих объектов CDemo.
Чтобы добавить код для конструктора и деструктора класса CDemo
В Редакторе кода добавьте переменные-члены для хранения общего числа экземпляров класса CDemo и идентификатора каждого экземпляра.
public readonly int InstanceID; private static int NextInstanceID = 0; private static long ClassInstanceCount = 0;
Поскольку переменные-члены InstanceCount и NextInstanceID объявлены как static, они существуют только на уровне класса. Все экземпляры объекта CDemo, обращающиеся к этим членам, используют один и тот же адрес в памяти. Статические члены инициализируются при первом обращении к классу CDemo в коде. Это может произойти при первом создании объекта CDemo или при первом обращении к одному из статических членов класса.
Найдите public CDemo() и public CDemo(IContainer container), конструктор по умолчанию для класса CDemo. В Visual C# все конструкторы имеют то же имя, что и класс. У компонента может быть несколько конструкторов, каждый со своими параметрами, но все они должны называться так же, как и компонент.
Примечание. Уровень доступа конструктора определяет, какие клиенты могут создавать экземпляры класса.
Добавьте в процедуру public CDemo() следующий код, увеличивающий счетчик экземпляров при создании нового экземпляра класса CDemo и задающий идентификатор экземпляра.
Примечание. Всегда добавляйте код после вызова метода InitializeComponent. На этом этапе все необходимые компоненты инициализированы.
InstanceID = NextInstanceID ++; ClassInstanceCount ++;
Для членов с разрешением readonly значение InstanceID можно задавать только в конструкторе.
Примечание. Пользователи, знакомые с многопоточностью, могут справедливо отметить, что назначение значения InstanceID и увеличение значения NextInstanceID должно быть неделимой операцией. Это, а также другие вопросы, связанные с многопоточностью, освещено в разделе Пошаговое руководство. Разработка простого многопоточного компонента с помощью Visual C#.
Добавьте в конец конструктора следующий метод:
~CDemo() { ClassInstanceCount --; }
Этот метод называется деструктором. Имя деструктора состоит из тильды (~), за которой следует имя класса. Диспетчер памяти вызывает деструктор непосредственно перед освобождением памяти, занимаемой объектом CDemo. Реализация деструктора позволяет выполнять операции по очистке непосредственно перед удалением компонента из памяти. Однако, как будет показано далее в этом пошаговом руководстве, существуют веские аргументы в пользу более раннего освобождения ресурсов.
Добавление свойства в класс
У класса CDemo есть только одно свойство. Это статическое свойство, позволяющее клиенту узнать число объектов CDemo в памяти на данный момент. Методы создаются аналогичным образом.
Чтобы создать свойство для класса CDemo
Добавьте в класс CDemo следующее объявление свойства, позволяющее клиентам извлекать число экземпляров класса CDemo.
public static long InstanceCount { get { return ClassInstanceCount; } }
Тестирование компонента
Чтобы протестировать компонент, необходим проект, в котором он используется. Этот проект должен запускаться первым при нажатии кнопки "Выполнить".
Чтобы добавить клиентский проект CDemoTest в качестве автозагружаемого проекта для решения
В меню Файл наведите указатель мыши на Добавить и выберите Создать проект, после чего открывается диалоговое окно Добавление нового проекта.
Выберите шаблон проекта Приложение Windows и введите CDemoTest в поле Имя, а затем щелкните ОК.
В окне Обозревателя решений щелкните правой кнопкой мыши CDemoTest, а затем из контекстного меню выберите Назначить автозагружаемым проектом.
Чтобы клиентский тестовый проект мог использовать компонент CDemo, он должен ссылаться на проект библиотеки классов. После добавления ссылки следует добавить в тестовое приложение оператор using, чтобы облегчить использование компонента.
Чтобы добавить ссылку на проект библиотеки классов
В Обозревателе решений щелкните правой кнопкой мыши узел Ссылки, расположенный непосредственно под CDemoTest, и выберите из контекстного меню команду Добавить ссылку.
В диалоговом окне Добавить ссылку перейдите на вкладку Проекты.
Дважды щелкните проект библиотеки классов CDemoLib. Под узлом Ссылки проекта CDemoTest появляется строка CDemoLib.
В Обозревателе решений щелкните правой кнопкой мыши Form1.cs и выберите из контекстного меню Просмотреть код.
Добавление ссылки на CDemoLib позволяет использовать полное имя компонента CDemo, т.е. CDemoLib.CDemo.
Чтобы добавить оператор "using"
Добавьте следующий оператор using к списку операторов using в верхней части Редактора кода для Form1:
using CDemoLib;
Оператор using позволяет опускать имя библиотеки и ссылаться на тип компонента по имени CDemo.
Далее будет создана тестовая программа для проверки компонента.
Основные сведения о времени жизни объекта
В программе CDemoTest демонстрируется время существовования объектов в платформе .NET Framework. Для этого создается и освобождается большое число объектов CDemo.
Чтобы добавить код для создания и освобождения объектов CDemo
Щелкните Form1.cs[Design], чтобы вернуться в конструктор.
Перетащите Button и Timer с вкладки Все формы Windows Forms в Панели инструментов на поверхность разработки Form1.
Невизуальный компонент Timer отображается на отдельной поверхности разработки ниже формы.
Дважды щелкните значок timer1, чтобы создать метод обработки событий для события Tick компонента timer1. Поместите в этот метод обработки событий следующий код:
this.Text = "CDemo instances: " + CDemo.InstanceCount;
По истечении каждого кванта времени таймера в подписи формы отображается текущее число экземпляров класса CDemo. В качестве квалификатора для статического свойства InstanceCount используется имя класса. Для обращения к статическому члену не требуется создавать экземпляр CDemo.
Найдите конструктор для Form1 (public Form1()) и после обращения к InitializeComponent() добавьте следующий код.
timer1.Enabled = true;
Это позволяет запустить таймер сразу после создания формы.
Щелкните вкладку Form1.cs[Design], чтобы вернуться в конструктор.
Дважды щелкните Button в форме Form1, чтобы создать метод обработки событий для события Click этой кнопки. Поместите в этот метод обработки событий следующий код:
CDemo cd; int ct; for (ct = 0; ct < 1000; ct++) cd = new CDemo();
Этот код может показаться странным. При каждом создании экземпляра CDemo предыдущий экземпляр освобождается. После окончания цикла for остается только один экземпляр CDemo. После выхода из метода обработки событий освобождается и этот экземпляр, так как переменная cd выходит за область действия.
Однако уже понятно, что дело обстоит не совсем так.
Чтобы запустить и выполнить отладку проектов CDemoTest и CDemo
Нажмите клавишу F5, чтобы запустить решение.
Запускается клиентский проект, и на экране отображается форма Form1. Обратите внимание, что в заголовке формы отображается "CDemo instances: 0".
Нажмите кнопку. В заголовке формы должна отображаться надпись "CDemo instances: 1000".
Все экземпляры CDemo были освобождены на момент завершения процедуры обработки события Click этой кнопки. Но почему тогда они не были завершены? Если не углубляться в детали, то диспетчер памяти завершает объекты в фоновом режиме с низким приоритетом. Этот приоритет повышается лишь в том случае, когда в системе не хватает свободной памяти. Эта схема отложенного сбора мусора позволяет очень быстро выделять память под объекты.
Нажмите эту кнопку еще несколько раз, следя за подписью формы. В некоторый момент число экземпляров внезапно резко снижается. Это означает, что диспетчер памяти освободил память, занимаемую ранее некоторыми из этих объектов.
Примечание. Если кнопка была нажата более 10 раз, а число экземпляров CDemo не уменьшилось, возможно, потребуется изменить код таким образом, чтобы он использовал больший объем памяти. Закройте форму, чтобы вернуться в среду разработки, и увеличьте число итераций цикла for до 10000. Затем снова запустите проект.
Повторите шаг 3. Теперь создается большее число объектов, прежде чем диспетчер памяти начинает завершать их.
На самом деле, при каждом повторении шага 3, возможно, удастся выделить память под большее число объектов CDemo до запуска диспетчера памяти. Дело в том, что все больший объем данных Visual Studio выгружается из памяти, освобождая пространство для экземпляров CDemo.
Закройте форму, чтобы вернуться в среду разработки.