Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Как связаны пространства имен и сборки





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

Например, тип System.IO.FileStream реализован в сборке MSCorLib.dll, a System.IO.FileSystemWatcher — в System.dll. В действительности сборка System.dll даже не поставляется в составе.NET Framework.

В одной сборке могут содержаться типы из разных пространств имен. Так, в сборке MSCorLib.dll находятся типы System.Int32 и System.Text.StringBuilder.

В документации.NET Framework SDK четко показано, к каким пространствам имен принадлежат те или иные типы и в каких сборках находятся реализации типов. На рис. 3.1 справа от раздела Syntax показано, что тип ResXFileRef относится к пространству имен SystemResources, однако его реализация находится в сборке System.Windows.Forms.dll. Чтобы скомпилировать код, ссылающийся на тип ResXFileRef следует добавить в код директиву using SystemResources; а также использовать параметр /r:System.Windows.Forms.dll компилятора.

 
 

 

Рис. 3.1. Сведения о пространстве имен и сборке для конкретного типа в документации к.NET Framework SDK


Элементарные, ссылочные и значимые типы

В этой главе речь идет о разновидностях типов, с которыми вы будете иметь дело при программировании для Microsoft.NET Framework. Важно, чтобы все разработчики четко осознавали разницу в их поведении. Приступая к изучению.NET Framework, я (Рихтер) толком не понимал, в чем разница между элементарными, ссылочными и значимыми типами, и поэтому невольно напустил в свой код трудно вылавливаемых «жучков» и снизил его эффективность. Надеюсь, мой опыт и объяснения разницы между этими типами помогут вам избавиться от лишней головной боли и повысить производительность работы.

Элементарные типы в языках программирования

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

System.Int32 а = new System.Int32();

 

Конечно, подобный синтаксис для объявления и инициализации целой переменной кажется громоздким. К счастью, многие компиляторы (включая С#) позволяют использовать и более простые выражения, например:

int a = 0;

 

Такой код читается намного лучше, да и компилятор в обоих случаях генерирует идентичный IL-код для System.Int32. Типы данных, которые поддерживаются компилятором напрямую, называются элементарными типами (primitive types) и отображаются им в типы из библиотеки классов.NET Framework Class Library (FCL). Так, С#-типу int соответствует System.Int32. Значит, весь следующий код компилируется без ошибок и преобразуется в одинаковые команды IL (в приведенном коде регистр символов важен):

int а = 0; // Самый удобный синтаксис

System.Int32 a = 0; // Удобный синтаксис

int a = new int(); // Неудобный синтаксис

System.Int32 a = new System.Int32(); // Самый неудобный синтаксис

 

В табл. 4.1 представлены типы FCL и соответствующие им элементарные типы С#. В других языках типам, удовлетворяющим общеязыковой спецификации Common Language Specification (CLS), будут соответствовать аналогичные элементарные типы. Однако поддержка языком типов, не удовлетворяющих требованиям CLS, необязательна.

 

Табл. 4.1. Элементарные типы С# и соответствующие типы FCL

Элементарный тип С# Тип FCL Совместимость c CLS Описание
sbyte System.SByte Нет 8-разрядное значение со знаком
byte System.Byte Да 8-разрядное значение без знака
short System.Intl6 Да 16-разрядное значение со знаком
ushort System.UIntl6 Нет 16-разрядное значение без знака
int System.Int32 Да 32-разрядное значение со знаком
uint System.UInt32 Нет 32-разрядное значение без знака
long System.Int64 Да 64-разрядное значение со знаком
ulong System.UInt64 Нет 64-разрядное значение без знака
char System.Char Да 16-разрядный символ Unicode (char никогда не представляет 8-разрядное значение, как в неуправляемом коде на C++)
float System.Single Да 32-разрядное float в стандарте IEЕЕ
double System.Double Да 64-разрядное float в стандарте IEEE
bool System.Boolean Да Булево значение (True или False)
decimal System.Decimal Да 128-разрядное значение с плавающей точкой повышенной точности, часто используемое для финансовых расчетов, где недопустимы ошибки округления. Один разряд числа — это знак, в следующих 96 разрядах помещается само значение, следующие 8 разрядов — степень числа 10, на которое делится 96-разрядное число (может быть в диапазоне от 0 до 28). Остальные разряды не используются
object System.Object Да Базовый тип для всех типов
string System.String Да Массив символов

 

Иначе говоря, можно полагать, что компилятор С# автоматически предполагает, что во всех файлах исходного кода есть следующие директивы using:

using sbyte = System.SByte;

using byte = System.Byte;

using short = System.Int16;

using ushort = System.UInt16;

using int = System.Int32;

using uint = System.UInt32;

 

Я не могу согласиться со следующим утверждением из спецификации языка С#: «С точки зрения стиля программирования предпочтительней использовать ключевое слово, а не полное системное имя типа». Я стараюсь использовать имена типов FCL и избегать имен элементарных типов. На самом деле мне бы хотелось, чтобы имен элементарных типов не было совсем, а разработчики употребляли только имена FCL-типов. И вот почему.

§ Мне попадались разработчики, не понимавшие, что использовать в коде: string или String. В С# это не важно, так как ключевое слово string в точности преобразуется в FCL-тип System.String.

§ В С# long отображается в System.Int64, но в другом языке это может быть Int16 или Int32. Как известно, в C++ с управляемыми расширениями long трактуется как Int32. Если кто-то возьмется читать код, написанный на новом для себя языке, то назначение кода может быть неверно им истолковано. Многим языкам незнакомо ключевое слово long, и их компиляторы не пропустят код, где оно встречается.

§ У многих FCL-типов есть методы, в имена которых включены имена типов. Например, у типа BinaryReader есть методы ReadBoolean, ReadInt32 и ReadSingle и т. д., а у типа System.Convert — методы ToBoolean, Tolnt32 и ToSingle и т. д. Вот вполне приемлемый код, в котором строка, содержащая float, кажется мне неестественной, и сразу не очевидно, что код корректный:

BinaryReader br = new BinaryReader(...);

float val = br.ReadSingle(); /* Код правильный, но выглядит

неестественно*/

Single val = br.ReadSingle(); /* Код правильный и выглядит

нормально*/

 

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

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

Int32 i=5; // 32-разрядное число

Int64 I = i; // Неявное приведение типа к 64-разрядному значению

 

Но, если вспомнить, что говорилось о приведении типов ранее, можно решить, что он компилироваться не будет. Все-таки System.Int32 и System.Int64 — разные типы и не приводятся друг к другу. Могу вас обнадежить: код успешно компилируется и делает все, что ему положено. Объясню, почему.

Дело в том, что компилятор С# неплохо разбирается в элементарных типах и применяет свои правила при компиляции кода. Иначе говоря, он распознает наиболее распространенные шаблоны программирования и генерирует такие IL-кoманды, благодаря которым исходный код работает, как требуется. В первую очередь это относится к приведению типов, литералам и операторам, примеры которых мы рассмотрим ниже.

Начнем с того, что компилятор выполняет явное и неявное приведение между элементарными типами, например:

Int32 i = 5; // Неявное приведение Int32 к Int32

Int64 I = i; // Неявное приведение Int32 к Int64

Single s = i; // Неявное приведение Int32 к Single

Byte b = (Byte) i; // Явное приведение Int32 к Byte

Int16 v = (Int16) s; // Явное приведение Single к Int16

 

С# разрешает неявное приведение типа, если это преобразование «безопасно», то есть не сопряжено с потерей данных; пример — преобразование из Int32 в Intб4. Однако для преобразования с риском потери данных С# требует явного приведения типа. Для числовых типов «небезопасное» преобразование означает «связанное с потерей точности или величины числа». Так, преобразование из Int32 в Byte требует явного приведения к типу, так как при больших величинах Int32 будет потеряна точность; требует приведения и преобразование из Single в Int64, поскольку число Single может оказаться больше, чем допустимо для Int64.

Разные компиляторы могут создавать различный код для выполнения приведения. Например, в случае приведения числа 6.8 типа Single к типу Int32 одни компиляторы создадут код, который поместит в Int32 число 6, а другие округлят результат до 7. Между прочим, в С# дробная часть всегда отбрасывается. Точные правила приведения для элементарных типов вы найдете в разделе спецификаций языка С#, посвященном преобразованиям («Conversions»).

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

Console.WriteLine(123.ToString() + 456.ToString()); // "123456"

 

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

Boolean found = false; // В готовом коде found присваивается 0

Int32 х = 100 + 20 + 3; // В готовом коде х присваивается 123

String s = "а " + "be"; // В готовом коде s присваивается "a be"

 

И, наконец, компилятор знает, как и в каком порядке интерпретировать встретившиеся в коде операторы (в том числе +, -, *, /, %, &, л, |, ==,!=, >, <, >=, <=, «,», ~,!, ++, -- и т. п.):

Int32 х = 100; // Оператор присваивания

Int32 у = х + 23; // Операторы суммирования и присваивания

Boolean LessThanFifty = (у < 50); // Операторы "меньше чем" и присваивания

 







Система охраняемых территорий в США Изучение особо охраняемых природных территорий(ООПТ) США представляет особый интерес по многим причинам...

Конфликты в семейной жизни. Как это изменить? Редкий брак и взаимоотношения существуют без конфликтов и напряженности. Через это проходят все...

ЧТО И КАК ПИСАЛИ О МОДЕ В ЖУРНАЛАХ НАЧАЛА XX ВЕКА Первый номер журнала «Аполлон» за 1909 г. начинался, по сути, с программного заявления редакции журнала...

Что способствует осуществлению желаний? Стопроцентная, непоколебимая уверенность в своем...





Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2024 zdamsam.ru Размещенные материалы защищены законодательством РФ.