Полное руководство. С# 4.0 - Шилдт Герберт
Шрифт:
Интервал:
Закладка:
Результат выполнения этой программы приведен ниже.Поместить символы А-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, 0t2.х, t2.у: 8, 9t3.х, 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 внедрено новое средство, повышающее удобство указания аргументов при вызове метода. Это средство называется необязательными аргументами ипозволяет определить используемое по умолчанию значение для параметра метода.Данное значение будет использоваться по умолчанию в том случае, если для параметра не указан соответствующий аргумент при вызове метода. Следовательно, указыватьаргумент для такого параметра не обязательно. Необязательные аргументы позволяютупростить вызов методов, где к некоторым параметрам применяются аргументы, выбираемые по умолчанию. Их можно также использовать в качестве "сокращенной"формы перегрузки методов.Применение необязательного аргумента разрешается при создании необязательногопараметра. Для этого достаточно указать используемое по умолчанию значение параметра с помощью синтаксиса, аналогичного инициализации переменной. Используемое по умолчанию значение должно быть константным выражением. В качествепримера рассмотрим следующее определение метода.