Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Объектно-ориентированное программирование.-6

.pdf
Скачиваний:
6
Добавлен:
05.02.2023
Размер:
4.5 Mб
Скачать

но выполнение программы – зеленой стрелкой. Строка кода, для которой установлена точка останова, отображается на красном фоне; текущая конструкция при отладке – на желтом фоне; конструкция, на которой было остановлено выполнение программы – на зеленом фоне (рис. 2.35).

Все эти действия доступны только из среды разработки. Дополнительные команды смотрите в меню «Отладка». Прервать выполнение программы из консоли позволяет нажатие комбинации клавиш Ctrl+C или закрытие окна консоли.

Для наблюдения за значениями локальных переменных, а также полей и свойств типов достаточно навести курсор мыши на экземпляр типа. Если тип содержит вложенные экземпляры, то их также можно разворачивать для просмотра (рис. 2.35).

Также при отладке отображаются окна с дополнительной информацией, в том числе:

«Видимые» – обзор значений видимых переменных, полей и свойств;

«Локальные» – обзор значений локальных переменных;

«Точки останова» – информация об имеющихся точках останова. Здесь можно некоторые точки удалить или отключить временно, а также задать условия останова;

«Стек вызовов» – содержимое стека вызовов.

Например, на рис. 2.36 среда разработки настроена так, что отображаются окна «Видимые» и «Стек вызовов».

Рис. 2.36 – Обзор значений переменных и стека вызовов

71

При возникновении в программе необработанной исключительной ситуации, среда разработки сигнализирует об этом, показывая окно с информацией об исключении и месте его появления в программе (рис. 2.37).

Рис. 2.37 – Необработанная исключительная ситуация

Если же программа была запущена без отладки (Ctrl+F5) или не из среды разработки, то отобразится окно с информацией об ошибке (рис. 2.38). При нажатии на кнопку «ОК» информация об исключении будет выведена на консоль, и затем приложение будет закрыто. При нажатии на кнопку «Отмена» будет запущен отладчик Visual Studio.

Рис. 2.38 – Ошибка приложения

После исправления всех ошибок времени исполнения в приложении можно построить его финальную версию (Release), выбрав соответствующий пункт в выпадающем списке на панели инструментов или в свойствах проекта («Проект» → «Свойства…», закладка «Построение»).

72

3. ОСНОВЫ ЯЗЫКА C#

У нас уже есть простая, но работающая программа. Можно приступать

кизучению конструкций языка C#, добавляя их к этой программе. Рассмотрим также алфавитный список ключевых слов языка C# с крат-

ким указанием их функций и разделов учебного пособия, в которых о них говорится более подробно (табл. 3.1).

Табл. 3.1 – Список ключевых слов языка C#

КС

Описание

Пункт

 

 

 

abstract

Абстрактный класс или член класса

4.2.1-2

 

 

 

as

Преобразование типов данных

3.3.3.7

 

 

 

base

Доступ к конструктору базового класса

4.4.2

 

Доступ к члену базового класса

4.7.2.2

 

 

 

bool

Логический тип данных

3.1.2.3

 

 

 

break

Завершение цикла

3.4.4.1

 

Завершение оператора выбора

3.4.2.2

 

 

 

byte

Целый тип данных

3.1.2.1

 

 

 

case

Ветвление оператора выбора

3.4.2.2

 

 

 

catch

Обработка исключительной ситуации

3.4.5.2

 

 

 

char

Символьный тип данных

3.1.2.4

 

 

 

checked

Включение проверки переполнения для целых типов

3.3.3.10

 

 

 

class

Описание класса

4.2

 

Ограничение параметров типа

5.1.2

 

 

 

const

Описание неизменной локальной переменной

3.1.6.3

 

Описание неизменного члена класса

4.3.1

 

 

 

continue

Переход на следующую итерацию цикла

3.4.4.2

 

 

 

decimal

Тип данных с плавающей точкой

3.1.2.2

 

 

 

default

Метка по умолчанию в операторе выбора

3.4.2.2

 

Значение типа по умолчанию

3.1

 

 

 

delegate

Описание делегата

4.8.2

 

 

 

do

Оператор цикла

3.4.3.2

 

 

 

double

Тип данных с плавающей точкой

3.1.2.2

 

 

 

else

Часть условного оператора

3.4.2.1

 

 

 

enum

Объявление перечисления

3.1.2.5

 

 

 

 

73

 

event

Объявление события

4.8.3

 

Описание атрибута события

5.4.1

 

 

 

explicit

Объявление оператора явного преобразования типов

4.7.3.4

 

 

 

extern

Объявление метода с внешней реализацией

4.2.2

 

Описание внешнего псевдонима

4.1.3.2

 

 

 

false

Логическая константа «ложь»

3.1.2.3

 

Логический оператор

3.3.3.3

 

 

 

finally

Завершение блока обработки исключительной ситуации

3.4.5.2

 

 

 

fixed

Объявление неперемещаемой переменной или буфера

5.5.2.3

 

 

 

float

Тип данных с плавающей точкой

3.1.2.2

 

 

 

for

Оператор цикла

3.4.3.3

 

 

 

foreach

Оператор цикла

3.4.3.4

 

 

 

goto

Переход на ветку оператора выбора

3.4.2.2

 

Переход на именованную метку

3.4.4.3

 

 

 

if

Условный оператор

3.4.2.1

 

 

 

implicit

Объявление оператора неявного преобразования типов

4.7.3.4

 

 

 

in

Часть оператора цикла foreach

3.4.3.4

 

Часть выражения запроса LINQ

 

 

 

int

Целый тип данных

3.1.2.1

 

 

 

interface

Объявление интерфейса

4.9.1

 

 

 

internal

Модификатор доступа

4.2.1-2

 

 

 

is

Проверяет совместимость объекта с заданным типом

3.3.3.9

 

 

 

lock

Блокировка фрагмента кода

5.2.3.2

 

 

 

long

Целый тип данных

3.1.2.1

 

 

 

namespace

Объявление пространства имен

4.1.1

 

 

 

new

Оператор создания экземпляра объекта

3.3.3.1

 

Сокрытие члена базового класса

4.2.1-2

 

Ограничение типов в универсальном объявлении

5.1.2

 

Часть выражения запроса LINQ

 

 

 

null

Пустая ссылка

3.1.3

 

 

 

object

Псевдоним класса Object

3.1.3

 

 

 

operator

Перегрузка встроенного оператора

4.7.3.1

 

 

 

out

Передача аргумента в метод по ссылке

4.4.1.1

 

 

 

override

Перегрузка абстрактного/виртуального члена класса

4.6.2.2

 

 

 

 

74

 

params

Произвольное количество аргументов метода

4.4.1.3

 

 

 

private

Модификатор доступа

4.2.1-2

 

 

 

protected

Модификатор доступа

4.2.1-2

 

 

 

public

Модификатор доступа

4.2.1-2

 

 

 

readonly

Модификатор доступа

4.3.2

 

 

 

ref

Передача аргумента в метод по ссылке

4.4.1.1

 

 

 

return

Прерывание выполнения метода

3.4.4.4

 

Описание атрибута возвращаемого значения

5.4.1

 

 

 

sbyte

Целый тип данных

3.1.2.1

 

 

 

sealed

Описание изолированного класса или члена класса

4.2.1-2

 

 

 

short

Целый тип данных

3.1.2.1

 

 

 

sizeof

Размер типа данных по значению

3.3.3.9

 

 

 

stackalloc

Выделение блока памяти в стеке

5.5.2.4

 

 

 

static

Объявление статического класса или члена класса

4.2.1-2

 

 

 

string

Псевдоним класса String

3.1.3.1

 

 

 

struct

Объявление структуры

3.1.2.6

 

Ограничение параметров типа

5.1.2

 

 

 

switch

Оператор выбора

3.4.2.2

 

 

 

this

Ссылка на текущий экземпляр класса

4.2.3

 

Объявление индексатора

4.5.2

 

Описание метода расширения

4.4.1.2

 

 

 

throw

Генерация исключительной ситуации

3.4.5.2

 

 

 

true

Логическая константа «истина»

3.1.2.3

 

Логический оператор

3.3.3.3

 

 

 

try

Блок обработки исключительных ситуаций

3.4.5.2

 

 

 

typeof

Получение метакласса типа

3.3.3.9

 

 

 

uint

Целый тип данных

3.1.2.1

 

 

 

ulong

Целый тип данных

3.1.2.1

 

 

 

unchecked

Выключение проверки переполнения

3.3.3.10

 

 

 

unsafe

Блок небезопасного (неуправляемого) кода

5.5.2.1

 

 

 

ushort

Целый тип данных

3.1.2.1

 

 

 

using

Использование пространства имен или псевдонима

4.1.2

 

Оператор управления ресурсами

3.5.3

 

 

 

virtual

Объявление виртуального члена класса

4.7.2.1

 

 

 

 

75

 

void

Объявление метода, не возвращающего значение

4.4.1

 

 

 

volatile

Объявление поля, изменяемого несколькими потоками

5.2.3.5

 

 

 

while

Оператор цикла

3.4.3.1

 

 

 

Также есть ряд контекстно-зависимых ключевых слов (табл. 3.2). Т.е. они считаются таковыми только в определенных конструкциях языка.

Табл. 3.2 – Контекстно-зависимые ключевые слова языка C#

КС

Описание

Пункт

 

 

 

add

Метод добавления обработчика события

4.8.3

 

 

 

alias

Описание внешнего псевдонима

4.1.3.2

 

 

 

ascending

Часть выражения запроса LINQ

 

 

 

assembly

Описание атрибута сборки

5.4.1

 

 

 

descending

Часть выражения запроса LINQ

 

 

 

by

Часть выражения запроса LINQ

 

 

 

equals

Часть выражения запроса LINQ

 

 

 

field

Описание атрибута поля

5.4.1

 

 

 

from

Часть выражения запроса LINQ

 

 

 

get

Описание метода чтения значения свойства

4.5.1.1

 

 

 

global

Псевдоним глобального пространства имен

4.1.3.2

 

 

 

group

Часть выражения запроса LINQ

 

 

 

into

Часть выражения запроса LINQ

 

 

 

join

Часть выражения запроса LINQ

 

 

 

let

Часть выражения запроса LINQ

 

 

 

method

Описание атрибута метода

5.4.1

 

 

 

module

Описание атрибута модуля

5.4.1

 

 

 

on

Часть выражения запроса LINQ

 

 

 

orderby

Часть выражения запроса LINQ

 

 

 

param

Описание атрибута параметра

5.4.1

 

 

 

partial

Частичное определение объекта или метода

4.2.1-2

 

 

 

property

Описание атрибута свойства

5.4.1

 

 

 

remove

Метод удаления обработчика события

4.8.3

 

 

 

select

Часть выражения запроса LINQ

 

 

 

set

Описание метода записи значения свойства

4.5.1.1

 

 

 

type

Описание атрибута типа

5.4.1

 

 

 

value

Доступ к записываемому значению свойства

4.5.1.1

 

 

 

 

76

 

 

Доступ к обработчику события

4.8.3

 

 

 

var

Объявление локальной переменной неявного типа

3.1.4

 

 

 

where

Ограничение типов в универсальном объявлении

5.1.2

 

Часть выражения запроса LINQ

 

 

 

yield

Управление настраиваемым итератором

3.4.4.6

 

 

 

Вне указанных конструкций они ключевыми словами не считаются. Например, можно объявить переменную с именем «value», но только вне описания свойства или события.

77

§ 3.1. Типы данных. Идентификаторы

Все типы данных делятся на два больших класса – типы данных по значению и типы данных по ссылке. Существуют и указатели, но их можно использовать только в небезопасном коде, о них мы поговорим позже, в § 5.5. Отметим одно важное отличие языка C# от языка C++. В языке C++ конструкция, подобная следующей:

<тип> <имя переменной>;

объявляет новую переменную типа <тип> с указанным именем. Причем для переменной сразу же выделяется место в памяти на стеке, а если тип – это класс, то после этого вызывается конструктор данного класса. В языке C# этого не происходит! Память нужно выделять самостоятельно, используя оператор new:

<тип> <имя переменной> = new <тип>([<аргументы конструктора>]);

Существуют и другие способы инициализации переменных, о них мы поговорим ниже.

Каждый тип данных имеет значение по умолчанию (т.е. значение, принимаемое при инициализации конструктором по умолчанию, если он доступен):

0 для целых типов;

0.0 для чисел с плавающей точкой;

false для булева типа;

'\u0000' для символьного типа;

0 для перечисляемого типа (даже если константа с таким значением не определена);

null для ссылочных типов;

пустое значение для обнуляемых типов.

Для получения значения по умолчанию в явном виде также используется ключевое слово default:

<тип> <имя переменной> = default(<тип>);

3.1.1. Базовый класс System.Object

Все объекты .NET имеют единый базовый класс – System.Object. Соответственно, все типы данных (а они, очевидно, также являются классами)

78

наследуются от Object. И все методы, объявленные в классе Object, доступны для любого типа данных C#. Самые полезные из них – это:

public virtual string ToString(); public virtual bool Equals(object obj);

public static bool Equals(object objA, object objB);

public static bool ReferenceEquals(object objA, object objB); public Type GetType();

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

Следующие два метода проверяют эквивалентность двух экземпляров классов .NET. Причем второй вариант метода, статический, реализован через первый, поэтому запись Object.Equals(A, B) эквивалентна записи A.Equals(B) (но не B.Equals(A)!). При перегрузке метода Equals также следует перегрузить метод GetHashCode (см. п. 4.7.3.5).

Пример, демонстрирующий перегрузку методов ToString и Equals:

class Five

{

public override string ToString()

{

return "Five";

}

public override bool Equals(object obj)

{

return obj.ToString() == "Seven";

}

public override int GetHashCode()

{

return base.GetHashCode();

}

}

class Seven

{

public override string ToString()

{

return "Seven";

}

public override bool Equals(object obj)

{

return obj.ToString() == "Seven";

}

public override int GetHashCode()

{

return base.GetHashCode();

}

79

}

static int Main(string[] args)

{

Five c5 = new Five(); Seven c7 = new Seven(); Console.WriteLine(c5); Console.WriteLine(c7);

Console.WriteLine(c5.Equals(c7));

Console.WriteLine(c7.Equals(c5)); Console.WriteLine(Object.Equals(c5, c7)); Console.WriteLine(Object.Equals(c7, c5)); return 0;

}

В данном примере мы пользуемся тем, что первый вариант метода Equals виртуальный, и перегружаем его (см. § 4.7). Также перегружаем методы ToString. Теперь класс Five считает, что он эквивалентен тому классу, чье строковое представление – «Seven». Класс Seven считает, что он также эквивалентен такому классу. В результате работы на консоль будет выведен следующий текст:

Five

Seven

True

False

True

False

Следовательно, в некоторых ситуациях запись A.Equals(B) не эквивалентна записи B.Equals(A).

Четвертый метод проверяет совпадение ссылок на объекты. Рассмотрим следующий пример:

int x1 = new int(); int y1 = x1;

Console.WriteLine("x1 = " + x1 + "; y1 = " + y1); Console.WriteLine(x1.Equals(y1) ? "x1 == y1" : "x1 != y1"); Console.WriteLine(Object.ReferenceEquals(x1, y1) ?

"ref x1 == ref y1" : "ref x1 != ref y1");

Object x2 = new Object(); Object y2 = x2;

Console.WriteLine("x2 = " + x2 + "; y2 = " + y2); Console.WriteLine(x2.Equals(y2) ? "x2 == y2" : "x2 != y2"); Console.WriteLine(Object.ReferenceEquals(x2, y2) ?

"ref x2 == ref y2" : "ref x2 != ref y2");

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

x1 = 0; y1 = 0

80