Рейтинговые книги
Читем онлайн C# для профессионалов. Том II - Симон Робинсон

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 126 127 128 129 130 131 132 133 134 ... 167

Изменение размера массивов

Массивы C# являются динамическими, то есть можно определить число элементов в каждой размерности во время компиляции (также, как в динамически выделяемых массивах в C++). Однако невозможно изменить их размер после того, как были созданы их экземпляры. Если требуется это сделать, необходимо рассмотреть другие связанные с этим классы в пространстве имен System.Collections в библиотеке базовых классов, таких как System.Collections.ArrayList. Однако в этом отношении C# не отличается от C++. Обычные массивы C++ не допускают изменение размера, но существует ряд классов стандартной библиотеки, которые предоставляют это свойство.

Перечисления

В C# можно определить перечисление с помощью синтаксиса, аналогичного синтаксису C++.

// допустимо в C++ или C#

enum TypeOfBuilding {Shop, House, OfficeBlock, School};

Отметим, однако, что заключительная точка с запятой в C# не обязательна, так как определение перечисления в C# является фактически определением структуры, а определения структур не требуют заключительной точки с запятой.

// допустимо только в C#

enum TypeOfBuilding {Shop, House, OfficeBlock, School}

Однако в C# перечисление должно быть именованным, в то время как в C++ задание имени для перечисления является необязательным. Также как в C++, элементы перечисления в C# нумеруются от нуля в сторону увеличения, если только специально не определено, что элемент должен иметь определенное значение.

enum TypeOfBuilding {Shop, House=5, OfficeBlock, School = 10}

// Shop будет иметь значение 0, OfficeBlock будет иметь значение 6

Способ, с помощью которого происходит доступ к значениям элементов, отличается в C#, так как в C# необходимо определять имя перечисления.

Синтаксис C++:

TypeOfBuilding MyHouse = House;

Синтаксис C#:

TypeOfBuilding MyHouse = TypeOfBuilding.House;

Можно рассматривать это как недостаток, так как синтаксис очень велик, не это в действительности отражает тот факт, что перечисления являются в C# значительно более мощными. В C# каждое перечисление является полноценной структурой производной из System.Enum) и поэтому имеет некоторые методы. В частности, для любого перечисленного значения можно сделать следующее:

TypeOfBuilding MyHouse = TypeOfBuilding.House;

string Result = MyHouse.ToString(); // Result будет содержать "House"

Это почти невозможно сделать в C++.

В C# это делается и другим способом, с помощью статического метода Parse() класса System.Enum, хотя синтаксис будет чуть более запутанным

TypeOfВuilding MyHouse = (TypeOfBuilding)Enum.Parse(typeof(TypeOfBuilding), "House", true);

Enum.Parse() возвращает объектную ссылку и должен быть явно преобразован (распакован) обратно в соответствующий тип enum. Первым параметром в Parse() является объект System.Тyре, который описывает, какое перечисление должна представлять строка. Второй параметр является строкой, а третий параметр указывает, должен ли игнорироваться регистр символов. Вторая перегружаемая версия опускает третий параметр и не игнорирует регистр символов.

C# позволяет также выбрать описанный ниже тип данных, используемый для хранения enum:

enum TypeOfBuiding : short {Shop, House, OfficeBlock, School};

Если тип не указан, компилятор будет предполагать по умолчанию int.

Исключения

Исключения используются в C# таким же образом, как и в C++, кроме двух следующих различий:

□ C# определяет блок finally, который содержит код, всегда выполняющийся в конце блока try независимо от того, порождалось ли какое-либо исключение. Отсутствие этого свойства C++ явилось причиной недовольства среди разработчиков C++. Блок finally выполняется, как только управление покидает блок catch или try, и содержит обычно код очистки выделенных в блоке try ресурсов.

□ В C++ класс, порожденный в исключении, может быть любым классом. C#, однако, требует, чтобы исключение было классом, производным от System.Exception.

Правила выполнения программы в блоках try и catch идентичны в C++ и C#. Используемый синтаксис также одинаков, за исключением одного различия: в C# блок catch, который не определяет переменную для получения объекта исключения, обозначается самой инструкцией catch. Синтаксис C++:

catch (...) {

Синтаксис C#.

catch {

В C# этот вид инструкции catch может быть полезен для перехвата исключений, которые порождаются кодом, написанным на других языках (и которые поэтому могут не быть производными от System.Exception, компилятор C# отметит ошибку, если попробовать определить такой объект-исключение, но это не имеет значения для других языков программирования).

Полный синтаксис для try…catch…finally в C# выглядит следующим образом:

try {

 // обычный код

} catch (MyException e) { // MyException выводится из System.Exception

 // код обработки ошибки

}

// необязательные дополнительные блоки catch

finally {

 // код очистки

}

Отметим, что блок finally является необязательным. Также допустимо не иметь блоков catch, в этом случае конструкция try…finally служит просто способом обеспечения, чтобы код в блоке finally всегда выполнялся, когда происходит выход из блока try. Это может быть полезно, например, если блок try содержит несколько инструкций return и требуется выполнить очистку ресурсов, прежде чем метод реально возвратит управление.

Указатели и небезопасный код

Указатели в C# используются почти таким же образом, как и в C++. Однако они могут объявляться и использоваться только в блоке небезопасного (ненадежного) кода. Любой метод можно объявить небезопасным (unsafe):

public unsafe void MyMethod() {

Можно альтернативно объявить любой класс или структуру небезопасными и:

unsafe class MyClass {

Объявление класса или структуры ненадежными означает, что все члены рассматриваются как ненадежные. Можно также объявить любое поле-член (но не локальные переменные) как ненадежное, если имеется поле-член типа указателя:

private unsafe int* рХ;

Можно также пометить блочный оператор как ненадежный следующим образом: 

unsafe {

 // инструкции, которые используют указатели

Синтаксис для объявления, доступа, разыменования и выполнения арифметических операций с указателями такой же, как и в C++:

// этот код будет компилироваться в C++ или C#

// и имеет одинаковый результат в обоих языках

int X = 10, Y = 20;

int *рХ = &Х;

*рХ = 30;

pХ = &Y;

++рХ; // добавляет sizeof(int) к рХ

Отметим, однако, следующие моменты.

□ В C# не допускается разыменовывать указатели void*, также нельзя выполнять арифметические операции над указателями void*. Синтаксис указателя void* был сохранен для обратной совместимости, для вызова внешних функций API, которые не знают о .NET и которые требуют указателей void* в качестве параметров.

□ Указатели не могут указывать на ссылочные типы (классы или массивы). Также они не могут указывать на структуры, которые содержат встроенные ссылочные типы в качестве членов. Это в действительности попытка защитить данные, используемые сборщиком мусора и средой выполнения .NET (хотя в C#, также как и в C++, если начать использовать указатели, почти всегда можно найти способ обойти любые ограничения, выполняя арифметические операции на указателях и затем разыменовывая их).

□ Помимо объявления соответствующих частей кода как ненадежных, необходимо также определять для компилятора флаг /unsafe при компиляции кода, который содержит указатели.

□ Указатели не могут указывать на переменные, которые встроены в ссылочные типы данных (например, членов класса), если только они не объявлены внутри инструкции fixed.

Фиксация донных в куче

Разрешается присвоить адрес типа данных значения указателю, даже если этот тип встроен как поле-член в ссылочный тип данных. Однако такой указатель должен быть объявлен внутри инструкции fixed. Причина этого в том, что ссылочные типы могут в любое время перемещаться в куче сборщиком мусора. Сборщик мусора знает о ссылках C# и может обновить их, как требуется, но он не знает об указателях. Следовательно, если указатель направлен на член класса в куче и сборщик мусора перемещает весь экземпляр класса, то будет указан неправильный адрес. Инструкция fixed не позволяет сборщику мусора перемещать указанный экземпляр класса во время выполнения блока fixed, гарантируя целостность значений указателей.

1 ... 126 127 128 129 130 131 132 133 134 ... 167
На этой странице вы можете бесплатно читать книгу C# для профессионалов. Том II - Симон Робинсон бесплатно.

Оставить комментарий