Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Характеристика платформы .NET Framework





Характеристика платформы.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

Открытый метод Описание
Equals Возвращает true, если два объекта имеют одинаковые значения
GetHashCode Возвращает хеш-код для значения данного объекта. Этот метод следует переопределить, если объекты типа используются в качестве ключа в хеш-таблице. Очень неудачно, что этот метод определен в Object, потому что большинство типов не служат ключами в хеш-таблице; этот метод уместнее было бы определить в интерфейсе
ToString По умолчанию возвращает полное имя типа {this.GetType().FullName). На практике этот метод переопределяют, чтобы он возвращал объект String, содержащий состояние объекта в виде строки. Например, переопределенные методы для таких фундаментальных типов, как Boolean и Int32, возвращают значения объектов в строковом виде. Кроме того, переопределение метода часто применяют при отладке: вызов такого метода позволяет получить строку, содержащую значения полей объекта. Считается, что ToString «знает» о CultureInfo, связанном с вызывающим потоком
GetType Возвращает экземпляр объекта, производного от Туре, который идентифицирует тип объекта, вызвавшего GetType. Возвращаемый объект Туре может использоваться с классами, реализующими отражение для получения информации о типе в виде метаданных. Метод GetType невиртуальный, его нельзя переопределить, поэтому классу не удастся исказить сведения о своем типе. Таков механизм обеспечения безопасности типов.

 

Кроме того, типы, производные от System.Object, имеют доступ к защищенным методам (см. табл. 3.2).

Табл. 3.2. Защищенные методы System.Object

Защищенный метод Описание
MemberwiseClone Этот невиртуальный метод создает новый экземпляр типа и присваивает полям нового объекта соответствующие значения объекта this. Возвращается ссылка на созданный экземпляр
Finalize Этот виртуальный метод вызывается, когда сборщик мусора определяет, что объект является мусором, но до возвращения занятой объектом памяти в кучу. В типах, требующих очистки при сборке мусора, следует переопределить этот метод

 

Пример с константой:

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

Элементарный тип С# Тип 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манды, благодаря которым исходный код работает, как требуется. В первую очередь это относится к приведению типов, литералам и операторам, примеры которых мы рассмотрим ниже.

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







ЧТО ПРОИСХОДИТ ВО ВЗРОСЛОЙ ЖИЗНИ? Если вы все еще «неправильно» связаны с матерью, вы избегаете отделения и независимого взрослого существования...

Что делает отдел по эксплуатации и сопровождению ИС? Отвечает за сохранность данных (расписания копирования, копирование и пр.)...

ЧТО ПРОИСХОДИТ, КОГДА МЫ ССОРИМСЯ Не понимая различий, существующих между мужчинами и женщинами, очень легко довести дело до ссоры...

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





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


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