Программирование >>  Программирование с использованием ajax 

1 ... 69 70 71 [ 72 ] 73 74 75 ... 396


private MyClass() {

Код конструктора.

И, наконец, подобным образом в класс можно добавлять и не используемые по умолчанию конструкторы, просто указанием параметров:

class MyClass {

public MyClass О {

Код конструктора по умолчанию.

public MyClass (int myint) {

Код конструктора не по умолчанию (с параметром myint) .

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

Деструкторы объявляются с помощью немного другого синтаксиса. Деструктор, используемый в .NET (и предоставляемый классом System.Object), называется Finalize, но не это имя применяется для объявления деструктора. Вместо переопределения Finalize используется следующий код:

class MyClass {

-MyClassО {

Тело деструктора.

То есть деструктор класса объявляется путем указания имени класса (как и конструктор) с префиксом ~ (тильда) впереди. Код в деструкторе выполняется на этапе сборки мусора, позволяя освобождать ресурсы. После вызова данного деструктора также осуществляются и неявные вызовы деструкторов базовых классов, в числе которых и вызов деструктора Finalize корневого класса System.Object. Подобный подход позволяет .NET Framework гарантировать их выполнение, поскольку в случае переопределения деструктора Finalize вызовы деструктором базовых классов нужно было бы выполнять явно, что потенциально опасно (о том, как вызывать методы базовых классов, более подробно рассказывается в следующей главе).

Последовательность выполнения конструкторов

в случае выполнения нескольких задач в конструкторах класса может быть удобнее размещать весь связанный с этим код в одном месте и получать те же преимущества, что и при разбиении кода на функции, о чем говорилось в главе 6. Это можно делать с помощью метода (как будет показано в главе 10), но язык С# предлагает один замечательный альтернативный вариант, а именно - позволяет конфигурировать любой конструктор так, чтобы перед выполнением своего собственного кода он вызывал какой-то другой конструктор.



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

Чтобы был создан экземпляр производного класса, сначала должен обязательно быть создан экземпляр его базового класса, а чтобы был создан экземпляр этого базового класса, сначала должен быть создан экземпляр его собственного базового класса, и т.д., вплоть до самого класса System.Object (который является для всех классов корневым). Поэтому, какой бы конструктор не использовался для создания экземпляра класса, первым все равно всегда вызывается конструктор System.Object .Object.

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

public class MyBaseClass {

public MyBaseClassО

public MyBaseClass (int i)

public class MyDerivedClass : MyBaseClass {

public MyDerivedClass0

ublic MyDerivedClass(int i) public MyDerivedClass(int i, int j)

В такой иерархии экземпляр класса MyDerivedClass может создаваться так:

MyDerivedClass myObj = new MyDerivedClass() ;

Тогда последовательность происходящих событий будет выглядеть следующим образом.

а Сначала будет выполняться код конструктора System.Object.Object.

a Затем будет выполняться код конструктора MyBaseClass .MyBaseClass.

□ И, наконец, последним будет выполняться код конструктора MyDerivedClass. MyDerivedClass.



В качестве альтернативного варианта экземпляр класса MyDerivedClass может создавать и так:

MyDerivedClass myObj = new MyDerivedClass(4);

Тогда последовательность событий будет выглядеть, как описано ниже.

□ Сначала будет выполняться код конструктора System.Object .Object, а Затем будет выполняться код конструктора MyBaseClass .MyBaseClass.

□ И, наконец, последним будет выполняться код конструктора MyDerivedClass. MyDerivedClass(int i).

И, наконец, экземпляр класса MyDerivedClass может создаваться еще и так:

MyDerivedClass myOb] = new MyDerivedClass(4, 8) ;

Это приведет к тому, что последовательность событий будет выглядеть следующим образом.

□ Сначала будет выполняться код конструктора System.Object.Object.

□ Затем будет выполняться код конструктора MyBaseClass.MyBaseClass.

а И, наконец, последним будет выполняться код конструктора MyDerivedClass. MyDerivedClass (int i, int j).

Такая система подходит для большинства случаев, но в некоторых ситуациях может потребоваться чуть больший контроль над происходящими событиями. Например, в случае применения последнего способа для создания экземпляра класса MyDerivedClass может быть необходимо, чтобы последовательность событий выглядела, как описано ниже.

а Первым выполнялся код конструктора System. Ob ject. Ob ject.

a Вторым-код конструктора MyBaseClass.MyBaseClass (int i).

a Третьим - код конструктора MyDerivedClass .MyDerivedClass (int i, int j).

Тогда код, в котором используется параметр int i, можно будет поместить в MyBaseClass (int i), а это значит, что у конструктора MyDerivedClass (int i, int j ) будет меньше работы - ему придется обрабатывать только параметр int j. (Здесь предполагается, что в обоих сценариях предназначение параметра int i выглядит идентично, что может не всегда быть так, но на практике при такой организации обычно именно так и бывает.) Язык С# позволяет при желании задавать подобное поведение.

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

public class MyDerivedClass : MyBaseClass {

public MyDerivedClass (int i, int j) : base(i)

Ключевое слово base инструктирует процесс создания экземпляров .NET использовать конструктор базового класса, у которого имеются заданные параметры. В данном примере у него есть только один параметр - типа int (значение которого является



1 ... 69 70 71 [ 72 ] 73 74 75 ... 396

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика