|
Характеристика платформы .NET FrameworkСтр 1 из 14Следующая ⇒ Характеристика платформы.NET Framework Состав.NET Framework
.NET Framework состоит из двух частей: общеязыковой исполняющей среды (common language runtime, CLR) и библиотеки классов (Framework Class Library, FCL). CLR предоставляет модель программирования, используемую во всех типах приложений. У CLR собственный загрузчик файлов, диспетчер памяти (сборщик мусора), система безопасности (безопасность доступа к коду), пул потоков и другое. Кроме того, CLR предоставляет объектно-ориентированную модель программирования, определяющую, как выглядят и ведут себя типы и объекты. Рис.1.1. Структура.NET Framework Base Class Library (BCL)
BCL — стандартная библиотека классов платформы «.NET Framework». Программы, написанные на любом из языков, поддерживающих платформу.NET, могут пользоваться классами и методами BCL — создавать объекты классов, вызывать их методы, наследовать необходимые классы BCL и т. д. В отличие от многих других библиотек классов, например, MFC, ATL/WTL или SmartWin, библиотека BCL не является некоей «надстройкой» над функциями операционной системы или над каким-либо API. Библиотеки BCL является органической частью самой платформы.NET Framework, её «родным» API. Её можно рассматривать как API виртуальной машины.NET. BCL обновляется с каждой версией.NET Framework.
В BCL объявлено около 30 пространств имён, вот некоторые из них: System Наиболее важное пространство имён. Включает в себя все примитивные типы языка C#: «пустой» тип Void, знаковые и беззнаковые целочисленные типы (например, Int32), типы чисел с плавающей запятой одинарной и двойной точности (Single, Double), «финансовый» тип Decimal, логический тип Boolean, символьный и строковый типы Char и String, а также, например, тип DateTime и другие. Обеспечивает также необходимым набором инструментов для работы с консолью, математическими функциями, и базовыми классами для атрибутов, исключений и массивов. System.Collections Определяет множество общих контейнеров или коллекций, используемых в программировании — такие как список, очередь, стек, хеш-таблица и некоторые другие. Также включена поддержка обобщений (Generics). System.Drawing Предоставляет доступ к GDI+, включая поддержку для 2D растровой и векторной графики, изображений, печати и работы с текстом. System.Text Поддерживает различные кодировки, регулярные выражения, и другие полезные механизмы для работы со строками(класс StringBuilder). System.Threading Облегчает мультипотоковое программирование. System.Timers Позволяет вызвать событие через определённый интервал времени.
Framework Class Library
FCL предоставляет объектно-ориентированный API-интерфейс, используемый всеми моделями приложений. В ней содержатся определения типов, которые позволяют разработчикам выполнять ввод/вывод, планирование задач в других потоках, создавать графические образы, сравнивать строки и т.д. и т.п. В ее состав входят библитеки, представленные на рис. 1.2.
Рис. 1.2 Состав FCL
Windows Workflow Foundation WWF или WF — уже не новая технология компании Microsoft, разработанная для создания и выполнения потоков работ (Workflow). Однако на данный момент она используется не очень активно, а многие разработчики вообще не слышали про нее. Ключевым понятием в WF является Активность (Activity) — класс, выполняющий единицу работы в среде выполнения WF. Термины Поток работ и Активность являются синонимами в контексте WF. Каждая Активность выполняет какое-либо действие — буквально программный код (например, на языке C#). Активности имеют входные и выходные параметры, переменные. Активность может представлять собой композицию из нескольких дочерних Активностей, в таком случае в процессе работы родительская Активность управляет запуском своих дочерних элементов в среде выполнения в соответствии со своей внутренней логикой. Например, Активность Parallel из базовой библиотеки Активностей (входит в поставку.NET Framework) запускает дочерние элементы параллельно. А поток работ if, как не сложно догадаться из названия, запускает один из двух дочерних элементов в зависимости от результата проверки заданного условия.
Таким образом, в конечном итоге создание потока работ обычно сводится к составлению в дизайнере блок-схемы на основе Активностей базовой библиотеки в сочетании с Активностями собственной разработки. Поток работ, построенный в дизайнере, кодируется на языке XAML (расширение XML). Неплохое понятие WF см. по адресу http://habrahabr.ru/company/luxoft/blog/181562/
Card Space Windows CardSpace — ныне отмененное клиентское ПО с патентованной технологией единого входа от Microsoft. WCS — это способ идентификации пользователей при перемещении между ресурсами Интернета без необходимости повторного ввода имен и паролей. В отличие от ранее используемых технологий унифицированной идентификации (например, Microsoft Passport) WCS управляет непосредственно пользователями и приложениями, с которыми устанавливается контакт (а не из централизованного ресурса). Можно применять разные схемы и уровни сложности для идентификации при доступе на Web-форумы и для банковских операций. 15 февраля 2011 корпорация Майкрософт объявила об отмене Windows CardSpace 2.0 и о работе над замещающим ПО U-Prove.
Task Parallel Library (TPL) Источник: https://msdn.microsoft.com/ru-ru/library/dd460717%28v=vs.110%29.aspx Библиотека параллельных задач (TPL) представляет собой набор открытых типов и API-интерфейсов в пространствах имен System.Threading и System.Threading.Tasks. Цель TPL — повышение производительности труда разработчиков за счет упрощения процедуры добавления параллелизма в приложения.TPL динамически масштабирует степень параллелизма для наиболее эффективного использования всех доступных процессоров. Кроме того, в библиотеке параллельных задач осуществляется секционирование работы, планирование потоков в пуле ThreadPool, поддержка отмены, управление состоянием и выполняются другие низкоуровневые задачи.Используя библиотеку параллельных задач, можно повысить производительность кода, сосредоточившись на работе, для которой предназначена программа. Начиная с.NET Framework 4 библиотека параллельных задач является предпочтительным способом создания многопоточного и параллельного кода.Однако не всякий код подходит для параллелизации; например, если цикл за каждую итерацию выполняет небольшой объем работ или выполняется для небольшого числа итераций, из-за дополнительной нагрузки, которую параллелизация оказывает на систему, код может выполняться медленнее.Кроме того, параллелизация, как и любой многопоточный код, усложняет выполнение программы.Хотя библиотека параллельных задач упрощает многопоточные сценарии, рекомендуется иметь базовое понимание понятий потоков, например блокировки, взаимоблокировки и состояния гонки, чтобы эффективно использовать библиотеку параллельных задач.
Parallel LINQ (PLINQ) Параллельный LINQ (PLINQ) является параллельной реализацией LINQ to Objects. PLINQ реализует полный набор стандартных операторов запроса LINQ как методы расширения для пространства имен T:System.Linq и имеет дополнительные операторы для параллельных операций. PLINQ объединяет простоту и удобство чтения синтаксиса LINQ с мощностью параллельного программирования. Подобно коду, предназначенному для библиотеки параллельных задач, запросы PLINQ масштабируют в степень параллелизма на основе возможностей главного компьютера. Во многих сценариях PLINQ может значительно увеличить скорость запросов LINQ, более эффективно используя все доступные ядра на главном компьютере. Повышенная производительность увеличивает вычислительную мощностью на рабочем столе.
Modern UI for WPF (MUI)
Набор элементов управления и стилей преобразования приложения WPF в современное приложение. Этот проект с открытым исходным кодом является побочным продуктом XAML Spy, визуального исполнения инспектора для Silverlight, Windows Phone, Windows Store и WPF.
Другие скрин-шоты см. https://github.com/firstfloorsoftware/mui/wiki/Screenshots
Task-Based Async Model Источник https://blogs.msdn.microsoft.com/dotnet/2012/04/03/async-in-4-5-worth-the-await/ Термин эффективность используется часто, когда речь идет о приложениях, но это на самом деле довольно расплывчатый термин. Есть по крайней мере, два аспекта эффективности: время запуска приложений и собственно производительности (throughput). Оба они могут быть измерены и описаны фактическими числами. Истинный тест приложения, однако, определяется восприятием конечного пользователя. Стоп-часы могут рассказать нам одну вещь, но пользователь может увидеть что-то другое. Восприятие конечного пользователя является основой асинхронности и связанных с ними функций, которые мы построили в.NET Framework 4.5. По существу, мы можем обеспечить более гибкий пользовательский интерфейс, если некоторые из более дорогих операций приложения могут быть отложены. Это позволит порадовать конечного пользователя и это поможет нам более эффективно использовать вычислительные ресурсы, чем было бы возможно ранее. В то время как вы всегда были в состоянии реализовать эту модель в.NET Framework, на практике реализация была проблематичной. Это было исправлено в.NET Framework 4.5 Beta. Продолжение см. https://blogs.msdn.microsoft.com/dotnet/2012/04/03/async-in-4-5-worth-the-await/
Примеры программ Все примеры даны для MVS 2008 на языке C#, если это не оговорено отдельно. Namespace MyNS { class MyProgram // public sealed static internal { public virtual void F() { } static void Main(String[] args) // static - обязательно { Console.WriteLine("args[0]={0}", args[0]); float[] Vec = new float[123]; foreach (int i in Vec) Vec[i] = 0; Switch (args.Length) { case 0: Console.WriteLine("Нет параметров"); break; case 1: Console.WriteLine(args[0]); break; case 2: Console.WriteLine(args[1]); break; default: Console.WriteLine("Слишком много параметров!"); break; } int k = 123; Console.WriteLine("k={0}, k={1}", k, k.ToString()); Console.WriteLine("Введи число>"); String s=Console.ReadLine(); // вводим число как строку символов k = Int32.Parse(s); Double d = Double.Parse(s); d = Convert.ToDouble(s); k = Int32.Parse(Console.ReadLine()); Console.ReadKey(); } } } /* MyFirstProgram 777 -> args[0]=MyFirstProgram k=123, k=123 */ Шаблонный класс список В данном подразделе иллюстрируются реализация собственного шаблонного класса односвязный список MyList, наследующего интерфейс IEnumerable (см. рис.3.1). IEnumerable – это базовый интерфейс для всех не обобщенных коллекций, которые могут быть перечислены. IEnumerable содержит один метод GetEnumerator(), который возвращает IEnumerator. IEnumerator предоставляет возможность выполнить перебор элементов коллекции с использованием свойства Current, методов MoveNext() и Reset(). Проект List. Полученный шаблонный класс MyList используется как родительский для класса SortedList, который реализует метод BubbleSort(), назначение и алгоритм которого раскрыт в его наименовании. В качестве единственного параметра шаблонного класса выступает простой класс Person, имеющий всего два атрибута: имя и возраст некоторого индивида. Рис. 3.1. Диаграммы классов приложения
Namespace GetCompProp { Class Program { static void Main(string[] args) { Console.WriteLine("System.Environment Class"); Console.WriteLine(); ShowEnvDetails(); Console.ReadKey(); } Чтение текстового файла
В данной программе иллюстрируется чтение данных разных типов из текстового файла. Содержимое файла может быть таким: Прогульщиков 12,5 1992 Ленивый 23,5 1993 Красивая 9060,90 1994
Разделителем полей записи выбран пробел, но пробел в конце записи файла не допускается. Текстовый файл с символами кириллицы надо сохранить в кодировке Unicode: File->Advanced Save Options->Encoding->Unicode (UTF-8...) - CodePage 65001 Файл проще всего разместить в каталоге debug проекта или использовать стандартный диалог по получению имени файла. Стандартный диалог по выбору имени файла можно организовать так: using System; using System.IO; /* необходимо для использования Directory.GetCurrentDirectory()*/ //using System.Collections.Generic; //using System.Linq; //using System.Text; //using System.ComponentModel; //using System.Data; //using System.Drawing; using System.Windows.Forms; /* необходимо для использования OpenFileDialog */ Class Program { [STAThreadAttribute]// необходимо для использования OpenFileDialog static void Main(string[] args) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.DefaultExt = "txt"; openFileDialog1.Filter = "Text files (*.txt)|*.txt"; openFileDialog1.InitialDirectory = Directory.GetCurrentDirectory(); if (openFileDialog1.ShowDialog() == DialogResult.OK) { /* читаем весь файл и выводим его содержимое в окно* StreamReader sr = new StreamReader(openFileDialog1.FileName); MessageBox.Show(sr.ReadToEnd()); sr.Close(); } } } Основы типов Табл. 3.1. Открытые методы System.Object
Кроме того, типы, производные от System.Object, имеют доступ к защищенным методам (см. табл. 3.2). Табл. 3.2. Защищенные методы System.Object
Пример с константой: Console.WriteLine("123.ToString()={0}", 123.ToString()); // 123 Console.WriteLine(" 123.GetType().FullName={0} ", 123.GetType().FullName); // 123.GetType().FullName=System.Int32
CLR требует, чтобы все объекты создавались с помощью оператора new (который порождает IL-команду newobj). Объект Employee создается так: Employee e = new Employee("ConstructorParam1");
Оператор new делает следующее. 1. Вычисляет число байт, необходимых всем экземплярным полям типа и всем его базовым типам вплоть до и включая System.Object (в котором отсутствуют собственные экземплярные поля). Каждый объект кучи требует дополнительных членов, они называются указатель на объект-тип (type object pointer) и индекс блока синхронизации {SyncBlockIndex) и используются CLR для управления объектом. Байты этих дополнительных членов добавляются к байтам, необходимым для размещения самого объекта. 2. Выделяет память для объекта, резервируя необходимое для данного типа число байт в управляемой куче байтов. 3. Инициализирует указатель на объект-тип и SyncBlockIndex. 4. Вызывает конструктор экземпляра типа с параметрами, указанными при вызове new (в предыдущем примере это строка «ConstructorParaml»). Хотя многие компиляторы помещают в конструктор вызов конструктора базового типа. Большинство компиляторов автоматически создает в конструкторе код вызова конструктора базового класса. Каждый конструктор выполняет инициализацию определенных в соответствующем типе полей. В частности, вызывается конструктор System.Object, но он ничего не делает и просто возвращает управление. Это легко проверить, загрузив в ILDasm.exe библиотеку MSCorLib.dll и изучив метод-конструктор типа System.Object.
Выполнив все эти операции, new возвращает ссылку (или указатель) на вновь созданный объект. В предыдущем примере кода эта ссылка сохраняется в переменной е типа Employee. Кстати, у оператора new нет пары — оператора delete, то есть нет явного способа освобождения памяти, занятой объектом. Сборкой мусора занимается CLR, которая автоматически находит объекты, ставшие ненужными или недоступными, и освобождает занимаемую ими память. Приведение типов Одна из важнейших особенностей CLR — безопасность типов (type safety). В период выполнения тип объекта всегда известен CLR. Точно определить тип объекта позволяет GetType. Поскольку это невиртуальный метод, никакой тип не сможет сообщить о себе ложные сведения. Так, тип Employee не может переопределить метод GetType, чтобы тот вернул тип SpaceShuttle. При разработке программ часто прибегают к приведению объекта к другим типам. CLR разрешает привести тип объекта к его собственному типу или любому из его базовых типов. Каждый язык программирования по-своему осуществляет приведение типов. Например, в С# нет специального синтаксиса для приведения типа объекта к его базовому типу, поскольку такое приведение считается безопасным неявным преобразованием. Однако для приведения типа к производному от него типу разработчик на С# должен ввести операцию явного приведения типов — неявное преобразование приведет к ошибке. Вот пример приведения к базовому и производному типам: // Этот тип неявно наследует типу System.Object Internal class Employee { ... } Public sealed class Program { Public static void Main() { /* Приведение типа не требуется, так как new возвращает объект Employee, a Object - это базовый тип для Employee*/ Object оbj = new Employee(); /* Приведение типа обязательно, так как Employee - производный от Object. В других языках (таких как Visual Basic) компилятор не потребует явного приведения*/ Employee emp = (Employee) оbj; } }
Этот пример демонстрирует, что необходимо компилятору для компиляции кода. А что произойдет в период выполнения? CLR проверит операции приведения, чтобы преобразования типов осуществлялись либо к фактическому типу объекта, либо к одному из его базовых типов. Вот код, который успешно компилируется, но в период выполнения вызывает исключение InvalidCastException: Internal class Employee { ... } Public sealed class Program { Public static void Main() { /* Создаем объект Manager и передаем его в PromoteEmployee. Manager ЯВЛЯЕТСЯ производным от Object, поэтому PromoteEmployee работает*/ Manager m = new Manager(); PromoteEmployee(m); /* Создаем объект DateTime и передаем его в PromoteEmployee. DateTime HE ЯВЛЯЕТСЯ производным от Employee, поэтому PromoteEmployee генерирует исключение System.InvalidCastException */ DateTime newYears = new DateTime(2007, 1, 1); PromoteEmployee(newYears); } If (оbj is Employee) { Employee emp = (Employee) obj; // Используем еmp внутри оператора if }
В этом коде CLR по сути проверяет тип объекта дважды: сначала в операторе is определяется совместимость obj с типом Employee, а затем в теле оператора if происходит анализ, является ли obj ссылкой на Employee. Контроль типов в CLR укрепляет безопасность, но при этом приходится жертвовать производительностью, так как CLR должна выяснять фактический тип объекта, на который ссылается переменная (obj), а затем проверить всю иерархию наследования на предмет наличия среди базовых типов заданного типа (Employee). Поскольку такая схема встречается в программировании часто, в С# предложен механизм, повышающий эффективность кода с помощью оператора as: Employee emp = оbj as Employee; if (emp!= null) { // Используем е внутри оператора if }
В этом коде CLR проверяет совместимость obj с типом Employee, если это так, as возвращает ненулевой указатель на этот объект. Если obj и Employee несовместимы, оператор as возвращает null. Заметьте: оператор as заставляет CLR верифицировать тип объекта только раз, a if лишь сравнивает еmp с null — такая проверка намного эффективнее, чем определение типа объекта. Оператор as отличается от приведения типа по сути только тем, что никогда не генерирует исключение. Если приведение типа невозможно, результатом является null. Если не сравнить полученный оператором результат с null и попытаться работать с пустой ссылкой, возникнет исключение NullReferenceException. Например, как показано здесь: System.Object оbj = new Object(); // Создание объекта Object Employee emp = obj as Employee; /* Приведение obj к типу Employee. Преобразование невыполнимо: исключение не возникло, но emp равно null*/ emp.ToString(); /* Обращение к emp вызывает исключение NullReferenceException */
Пространства имен и сборки Пространства имен позволяют объединять родственные типы в логические группы, в них проще найти нужный разработчику тип. Например, в пространстве имен System.Text описаны типы для обработки строк, а в пространстве имен System.IO — типы для выполнения операций ввода-вывода. В следующем коде создаются объекты System.IO.FileStream и System.Text.StringBuilder: using System; Public sealed class Program { Public static void Main() { System.IO.FileStream fs = new System.IO.FileStream(...); System.Text.StringBuilder sb = new System.Text.StringBuilder(); } }
Этот код грешит многословием — он станет изящнее, если обращение к типам FileStream и StringBuilder будет компактнее. К счастью, многие компиляторы предоставляют программистам механизмы, позволяющие сократить объем набираемого текста. Так, в компиляторе С# предусмотрена директива using, а в Visual Basic — оператор Imports. Этот код аналогичен предыдущему: using System.I0; // Попробуем избавиться от приставок "System.I0" using System.Text; // Попробуем избавиться от приставок "System.Text" Public sealed class Program { Public static void Main() { FileStream fs = new FileStream(...); StringBuilder sb = new StringBuilder(); } }
Для компилятора пространство имен — просто способ, позволяющий расширить имя типа и сделать его уникальным за счет добавления к началу имени групп символов, разделенных точками. Так, в нашем примере компилятор интерпретирует FileStream как System.IO.FileStream, a StringBuilder — как System.Text.StringBuilder. Применять директиву using в С# и оператор Imports в Visual Basic не обязательно; можно набирать и полное имя типа. Директива using заставляет компилятор С# добавить к имени указанный префикс и «попытаться» найти подходящий тип. В предыдущем примере компилятор должен гарантировать, что каждый упомянутый в коде тип существует и корректно обрабатывается: вызываемые методы существуют, число и типы передаваемых аргументов указаны правильно, значения, возвращаемые методами, обрабатываются надлежащим образом и т. д. Не найдя тип с заданным именем в исходных файлах и в перечисленных сборках, компилятор попытается добавить к имени типа приставку System.IO. и проверит, совпадает ли полученное имя с существующим типом. Если имя типа опять не обнаружено, он попробует повторить поиск уже с приставкой System.Text. Благодаря двум директивам using, показанным выше, я смог ограничиться именами FileStream и StringBuilder — компилятор автоматически расширит ссылки до System.IO.FileStream и System.Collections.StringBuilder. Полагаю, вам понятно, что вводить такой код намного проще, чем первоначальный. Компилятору надо сообщить с помощью параметра /reference, в каких сборках искать описание типа. В поисках нужного типа компилятор просмотрит все известные ему сборки. Если подходящая сборка найдена, сведения о ней и типе помещаются в метаданные результирующего управляемого модуля. Чтобы информация из сборки была доступна компилятору, надо указать ему сборку, в которой описаны упоминаемые типы. По умолчанию компилятор С# автоматически просматривает сборку MSCorLib.dll, даже если она явно не указана. В ней содержатся описания всех фундаментальных FCL-типов, таких как Object, Int32, String и другие. Легко догадаться, что такой способ обработки пространства имен чреват проблемами, если два (и более) типа с одинаковыми именами находятся в разных сборках. Microsoft настоятельно рекомендует при описании типов применять уникальные имена. Но порой это невозможно. В CLR поощряется повторное использование компонентов. Допустим, в приложении имеются компоненты, созданные в Microsoft и Wintellect, в которых есть типы с одинаковым названием, например Widget. В этом случае процесс формирования имен типов становится неуправляем, и, чтобы различать эти типы, придется указывать в коде их полные имена. При обращении к Widget от Microsoft надо указать MicrosoftWidget, а при ссылке на Widget от Wintellect — WintellectWidget. В следующем коде ссылка на Widget неоднозначна, и компилятор С# выдаст сообщение «error CS0104: 'Widget' is an ambiguous reference» («ошибка CS0104: 'Widget' — неоднозначная ссылка»): using Microsoft; // Определяем приставку "Microsoft." using Wintellect; // Определяем приставку "Wintellect." Public sealed class Program { Public static void Main() { Widget w = new Widget(); // Неоднозначная ссылка } }
Чтобы избавиться от неоднозначности, надо явно указать компилятору, какой экземпляр Widget требуется создать: using Microsoft; // Определяем приставку "Microsoft." using Wintellect; // Определяем приставку "Wintellect." Public sealed class Program { Public static void Main() { Wintellect.Widget w = new Wintellect.Widget(); /* Неоднозначности нет*/ } }
В С# есть еще одна форма директивы using, позволяющая создать псевдоним для отдельного типа или пространства имен. Она удобна, если требуется несколько типов из пространства имен, но не хочется смешивать в глобальном пространстве имен все используемые типы. Альтернативный способ преодоления неоднозначности таков: using Microsoft; // Определяем приставку "Microsoft." using Wintellect; // Определяем приставку "Wintellect." // Опишем символ WintellectWidget как псевдоним для Wintellect.Widget. using WintellectWidget = Wintellect.Widget; Public sealed class Program { Public static void Main() { WintellectWidget w = new WintellectWidgetQ; // Ошибки нет } }
Эти методы устранения неоднозначности хороши, но иногда их недостаточно. Представьте, что компании Australian Boomerang Company (ABC) и Alaskan Boat Corporation (ABC) создали каждая свой тип с именем BuyProduct и собираются поместить его в соответствующие сборки. Не исключено, что обе создадут пространства имен ABC, в которые и включат тип BuyProduct. Тот, кто намерен разработать приложение, оперирующее обоими типами, не сдвинется с места, если в языке программирования не окажется способа различать программными средствами не только пространства имен, но и сборки. К счастью в компиляторе С# поддерживается функция внешние псевдонимы (extern aliases), позволяющая справиться с такой проблемой. Внешние псевдонимы также позволяют обращаться к одному типу двух (или более) версий одной сборки. Подробнее о внешних псевдонимах см. спецификацию языка С#. При проектировании типов, применяемых в библиотеках, которые могут использоваться третьими лицами, старайтесь описывать эти типы в пространстве имен так, чтобы компиляторы могли без труда преодолеть неоднозначность типов. Вероятность конфликта заметно снизится, если в названии пространства имен верхнего уровня указать полное, а не сокращенное имя компании. В документации.NET Framework SDK Microsoft использует пространство имен «Microsoft» для своих типов (к примеру, пространства имен Microsoft.CSharp, Microsoft.VisualBasic и Microsoft.Win32). Чтобы создать пространство имен, достаточно ввести в код его объявление (на С#): Namespace CompanyName { Public sealed class A { // TypeDef: CompanyName.A } Namespace X { public sealed class В {... } // TypeDef: CompanyName.X.В } }
В комментарии справа от объявления класса указано реальное имя типа, которое компилятор поместит в таблицу метаданных определения типов; это настоящее имя типа с точки зрения CLR. Одни компиляторы вовсе не поддерживают пространства имен, а другие под термином «namespace» понимают нечто иное. В С# директива namespace инструктирует компилятор добавлять к каждому имени типа определенную приставку — это избавляет программиста от необходимости писать массу лишнего кода. Табл. 4.1. Элементарные типы С# и соответствующие типы FCL
Иначе говоря, можно полагать, что компилятор С# автоматически предполагает, что во всех файлах исходного кода есть следующие директивы 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манды, благодаря которым исходный код работает, как требуется. В первую очередь это относится к приведению типов, литералам и операторам, примеры которых мы рассмотрим ниже. Начнем с того, что компилятор выполняет явное и неявное приведение между э ЧТО ПРОИСХОДИТ ВО ВЗРОСЛОЙ ЖИЗНИ? Если вы все еще «неправильно» связаны с матерью, вы избегаете отделения и независимого взрослого существования... Что делает отдел по эксплуатации и сопровождению ИС? Отвечает за сохранность данных (расписания копирования, копирование и пр.)... ЧТО ПРОИСХОДИТ, КОГДА МЫ ССОРИМСЯ Не понимая различий, существующих между мужчинами и женщинами, очень легко довести дело до ссоры... ЧТО И КАК ПИСАЛИ О МОДЕ В ЖУРНАЛАХ НАЧАЛА XX ВЕКА Первый номер журнала «Аполлон» за 1909 г. начинался, по сути, с программного заявления редакции журнала... Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:
|