Чтение онлайн

на главную - закладки

Жанры

Полное руководство. С# 4.0
Шрифт:

Одна из самых распространенных причин для перегрузки конструкторов заключа ется в необходимости предоставить возможность одним объектам инициализировать другие. В качестве примера ниже приведен усовершенствованный вариант разработан ного ранее класса Stack, позволяющий конструировать один стек из другого. // Класс для хранения символов в стеке. using System; class Stack { // Эти члены класса являются закрытыми. char[] stck; // массив, содержащий стек int tos; // индекс вершины стека // Сконструировать пустой объект класса Stack по заданному размеру стека. public Stack(int size) { stck = new char[size]; // распределить память для стека tos = 0; } // Сконструировать объект класса Stack из существующего стека. public Stack(Stack ob) { // Распределить память для стека. stck = new char[ob.stck.Length]; // Скопировать элементы в новый стек. for(int i=0; i < ob.tos; i++) stck[i] = ob.stck[i]; // Установить переменную tos для нового стека. tos = ob.tos; } // Поместить символы в стек. public void Push(char ch) { if (tos==stck.Length) { Console.WriteLine(" -

Стек заполнен."); return; } stck[tos] = ch; tos++; } // Извлечь символ из стека. public char Pop { if (tos==0) { Console.WriteLine(" - Стек пуст."); return (char) 0; } tos--; return stck[tos]; } // Возвратить значение true, если стек заполнен. public bool IsFull { return tos==stck.Length; } // Возвратить значение true, если стек пуст. public bool IsEmpty { return tos==0; } // Возвратить общую емкость стека. public int Capacity { return stck.Length; } // Возвратить количество объектов, находящихся в настоящий момент в стеке. public int GetNum { return tos; } } // Продемонстрировать применение класса Stack. class StackDemo { static void Main { Stack stk1 = new Stack(10); char ch; int i; // Поместить ряд символов в стек stk1. Console.WriteLine("Поместить символы А-J в стек stk1."); for(i=0; !stk1.IsFull; i++) stk1.Push((char) ('A' + i)); // Создать копию стека stck1. Stack stk2 = new Stack(stk1); // Вывести содержимое стека stk1. Console.Write("Содержимое стека stk1: "); while( !stk1.IsEmpty ) { ch = stk1.Pop; Console.Write(ch); } Console.WriteLine; Console.Write("Содержимое стека stk2: "); while( !stk2.IsEmpty ) { ch = stk2.Pop; Console.Write(ch); } Console.WriteLine("\n"); } }

Результат выполнения этой программы приведен ниже. Поместить символы А-J в стек stk1. Содержимое стека stk1: JIHGFEDCBA Содержимое стека stk2: JIHGFEDCBA

В классе StackDemo сначала конструируется первый стек (stk1), заполняемый символами. Затем этот стек используется для конструирования второго стека (stk2). Это приводит к выполнению следующего конструктора класса Stack. // Сконструировать объект класса Stack из существующего стека. public Stack(Stack ob) { // Распределить память для стека. stck = new char[ob.stck.Length]; // Скопировать элементы в новый стек. for(int i=0; i < ob.tos; i++) stck[i] = ob.stck[i]; // Установить переменную tos для нового стека. tos = ob.tos; }

В этом конструкторе сначала распределяется достаточный объем памяти для мас сива, чтобы хранить в нем элементы стека, передаваемого в качестве аргумента ob. За тем содержимое массива, образующего стек ob, копируется в новый массив, после чего соответственно устанавливается переменная tos, содержащая индекс вершины стека. По завершении работы конструктора новый и исходный стеки существуют как отдель ные, хотя и одинаковые объекты.

Вызов перегружаемого конструктора с помощью ключевого слова this Когда приходится работать с перегружаемыми конструкторами, то иногда очень по лезно предоставить возможность одному конструктору вызывать другой. В С# это дает ся с помощью ключевого слова this. Ниже приведена общая форма такого вызова. имя_конструктора(список_параметров1) : this(список_параметров2) { // ... Тело конструктора, которое может быть пустым. }

В исходном конструкторе сначала выполняется перегружаемый конструктор, спи сок параметров которого соответствует критерию список_параметров2, а затем все остальные операторы, если таковые имеются в исходном конструкторе. Ниже приве ден соответствующий пример. // Продемонстрировать вызов конструктора с помощью ключевого слова this. using System; class XYCoord { public int x, y; public XYCoord : this(0, 0) { Console.WriteLine("В конструкторе XYCoord"); } public XYCoord(XYCoord obj) : this(obj.x, obj.y) { Console.WriteLine("В конструкторе XYCoord(obj)"); } public XYCoord(int i, int j) { Console.WriteLine("В конструкторе XYCoord(int, int)"); x = i; у = j; } } class OverloadConsDemo { static void Main { XYCoord t1 = new XYCoord; XYCoord t2 = new XYCoord(8, 9); XYCoord t3 = new XYCoord(t2); Console.WriteLine("t1.x, t1.y: " + t1.x + ", " + t1.y); Console.WriteLine("t2.x, t2.y: " + t2.x + ", " + t2.y); Console.WriteLine("t3.x, t3.y: " + t3.x + ", " + t3.y); } }

Выполнение этого кода приводит к следующему результату. В конструкторе XYCoord(int, int) В конструкторе XYCoord В конструкторе XYCoord(int, int) В конструкторе XYCoord(int, int) В конструкторе XYCoord(obj) t1.х, t1.у: 0, 0 t2.х, t2.у: 8, 9 t3.х, t3.у: 8, 9

Код в приведенном выше примере работает следующим образом. Единственным конструктором, фактически инициализирующим поля х и у в классе XYCoord, явля ется конструктор XYCoord(int, int). А два других конструктора просто вызывают этот конструктор с помощью ключевого слова this. Например, когда создается объект t1, то вызывается его конструктор XYCoord, что приводит к вызову this(0, 0), который в данном случае преобразуется в вызов конструктора XYCoord(0, 0). То же самое происходит и при создании объекта t2.

Вызывать перегружаемый конструктор с помощью ключевого слова this полез но, в частности, потому, что он позволяет исключить

ненужное дублирование кода. В приведенном выше примере нет никакой необходимости дублировать во всех трех конструкторах одну и ту же последовательность инициализации, и благодаря при менению ключевого слова this такое дублирование исключается. Другое преимуще ство организации подобного вызова перезагружаемого конструктора заключается в возможности создавать конструкторы с задаваемыми "по умолчанию" аргументами, когда эти аргументы не указаны явно. Ниже приведен пример создания еще одного конструктора XYCoord. public XYCoord(int х) : this(х, х) { }

По умолчанию в этом конструкторе для координаты у автоматически устанавли вается то же значение, что и для координаты у. Конечно, пользоваться такими кон струкциями с задаваемыми "по умолчанию" аргументами следует благоразумно и осторожно, чтобы не ввести в заблуждение пользователей классов. Инициализаторы объектов

Инициализаторы объектов предоставляют еще один способ создания объекта и ини циализации его полей и свойств. (Подробнее о свойствах речь пойдет в главе 10.) Если используются инициализаторы объектов, то вместо обычного вызова конструктора класса указываются имена полей или свойств, инициализируемых первоначально зада ваемым значением. Следовательно, синтаксис инициализатора объекта предоставляет альтернативу явному вызову конструктора класса. Синтаксис инициализатора объекта используется главным образом при создании анонимных типов в LINQ-вьгражениях. (Подробнее об анонимных типах и LINQ-вьгражениях — в главе 19.) Но поскольку ини циализаторы объектов можно, а иногда и должно использовать в именованном классе, то ниже представлены основные положения об инициализации объектов.

Обратимся сначала к простому примеру. // Простой пример, демонстрирующий применение инициализаторов объектов. using System; class MyClass { public int Count; public string Str; } class ObjInitDemo { static void Main { // Сконструировать объект типа MyClass, используя инициализаторы объектов. MyClass obj = new MyClass { Count = 100, Str = "Тестирование" }; Console.WriteLine(obj.Count + " " + obj.Str); } } Выполнение этого кода дает следующий результат.

100 Тестирование Как показывает результат выполнения приведенного выше кода, переменная экзем пляра obj.Count инициализирована значением 100, а переменная экземпляра obj. Str — символьной строкой "Тестирование". Но обратите внимание на то, что в клас се MyClass отсутствуют явно определяемые конструкторы и не используется обычный синтаксис конструкторов. Вместо этого объект obj класса MyClass создается с помо щью следующей строки кода.

MyClass obj = new MyClass { Count = 100, Str = "Тестирование" }; В этой строке кода имена полей указываются явно вместе с их первоначальными значениями. Это приводит к тому, что сначала конструируется экземпляр объекта типа MyClass (с помощью неявно вызываемого по умолчанию конструктора), а затем задаются первоначальные значения переменных Count и Str данного экземпляра. Следует особо подчеркнуть, что порядок указания инициализаторов особого зна чения не имеет. Например, объект obj можно было бы инициализировать и так, как показано ниже.

MyClass obj = new MyClass { Str = "Тестирование", Count = 100 }; В этой строке кода инициализация переменной экземпляра Str предшествует инициализации переменной экземпляра Count, а в приведенном выше коде все про исходило наоборот. Но в любом случае результат получается одинаковым. Ниже приведена общая форма синтаксиса инициализации объектов:

new имя_класса {имя = выражение, имя = выражение, ...} где имя обозначает имя поля или свойства, т.е. доступного члена класса, на который указывает имя_класса. А выражение обозначает инициализирующее выражение, тип которого, конечно, должен соответствовать типу поля или свойства. Инициализаторы объектов обычно не используются в именованных классах, как, на пример, в представленном выше классе MyClass, хотя это вполне допустимо. Вообще, при обращении с именованными классами используется синтаксис вызова обычного конструктора. И, как упоминалось выше, инициализаторы объектов применяются в основном в анонимных типах, формируемых в LINQ-выражениях. ## Необязательные аргументы В версии C# 4.0 внедрено новое средство, повышающее удобство указания аргу ментов при вызове метода. Это средство называется необязательными аргументами и позволяет определить используемое по умолчанию значение для параметра метода. Данное значение будет использоваться по умолчанию в том случае, если для параме тра не указан соответствующий аргумент при вызове метода. Следовательно, указывать аргумент для такого параметра не обязательно. Необязательные аргументы позволяют упростить вызов методов, где к некоторым параметрам применяются аргументы, вы бираемые по умолчанию. Их можно также использовать в качестве "сокращенной" формы перегрузки методов. Применение необязательного аргумента разрешается при создании необязательного параметра. Для этого достаточно указать используемое по умолчанию значение па раметра с помощью синтаксиса, аналогичного инициализации переменной. Исполь зуемое по умолчанию значение должно быть константным выражением. В качестве примера рассмотрим следующее определение метода.

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

Граф Суворов 7

Шаман Иван
7. Граф Суворов
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Граф Суворов 7

Шлейф сандала

Лерн Анна
Фантастика:
фэнтези
6.00
рейтинг книги
Шлейф сандала

Изгой Проклятого Клана

Пламенев Владимир
1. Изгой
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Изгой Проклятого Клана

Магия чистых душ

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.40
рейтинг книги
Магия чистых душ

Очешуеть! Я - жена дракона?!

Амеличева Елена
Фантастика:
юмористическая фантастика
5.43
рейтинг книги
Очешуеть! Я - жена дракона?!

Кодекс Крови. Книга ХII

Борзых М.
12. РОС: Кодекс Крови
Фантастика:
боевая фантастика
попаданцы
5.00
рейтинг книги
Кодекс Крови. Книга ХII

Газлайтер. Том 3

Володин Григорий
3. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 3

Бестужев. Служба Государевой Безопасности. Книга 5

Измайлов Сергей
5. Граф Бестужев
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бестужев. Служба Государевой Безопасности. Книга 5

Ученик

Губарев Алексей
1. Тай Фун
Фантастика:
фэнтези
5.00
рейтинг книги
Ученик

Жена по ошибке

Ардова Алиса
Любовные романы:
любовно-фантастические романы
7.71
рейтинг книги
Жена по ошибке

Как я строил магическую империю 6

Зубов Константин
6. Как я строил магическую империю
Фантастика:
попаданцы
аниме
фантастика: прочее
фэнтези
5.00
рейтинг книги
Как я строил магическую империю 6

Измена. Право на счастье

Вирго Софи
1. Чем закончится измена
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Право на счастье

Игра престолов

Мартин Джордж Р.Р.
Фантастика:
фэнтези
5.00
рейтинг книги
Игра престолов

Фараон

Распопов Дмитрий Викторович
1. Фараон
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Фараон