Операторы checked и unchecked используются для управления контекстом контроля переполненияв арифметических операциях и преобразованиях целых типов.
оператор_checked: checked блок
оператор_unchecked: unchecked блок
Оператор checked задает вычисление всех выражений в блоке в проверяемом контексте, а оператор unchecked задает вычисление всех выражений в блоке в непроверяемом контексте.
Операторы языка checked и unchecked в точности эквивалентны операторам выражений checked и unchecked (§7.6.12), только они применяются к блокам, а не к выражениям.
Lock
Оператор lock устанавливает взаимоисключающую блокировку для заданного объекта, выполняет оператор языка и затем снимает блокировку.
оператор_lock: lock ( выражение ) внедренный_оператор
Выражение оператора lock должно представлять значение, тип которого точно является ссылочным_типом. Для выражения оператора lock никогда не выполняется неявное преобразование с упаковкой (§6.1.7); использование выражения для представления значения, тип которого является типом_значения, вызывает ошибку времени компиляции.
Оператор lock следующего вида:
lock (x) ...
где x — выражение ссылочного_типа, в точности эквивалентен записи
за исключением того, что x вычисляется только один раз.
При установленной взаимоисключающей блокировке код, выполняемый в том же потоке выполнения, также может установить и снять блокировку. Однако код, выполняемый в других потоках, не сможет установить блокировку, пока не будет снята данная блокировка.
Не рекомендуется блокировать объекты System.Type для синхронизации доступа к статическим данным. Этот же тип может быть заблокирован другим кодом, что приведет к взаимоблокировке. Синхронизировать доступ к статическим данных лучше путем блокировки закрытого статического объекта. Пример:
class Cache { private static readonly object synchronizationObject = new object();
Оператор using получает один или несколько ресурсов, выполняет заданный оператор языка и затем удаляет ресурсы.
оператор_using: using ( выделение_ресурса ) внедренный_оператор
получение_ресурса: объявление_локальной_переменной выражение
Ресурс — это класс или структура, реализующая интерфейс System.IDisposable, который состоит из одного метода без параметров с именем Dispose. Код, использующий ресурс, может вызвать метод Dispose, чтобы показать, что ресурс больше не нужен. Если не вызывать метод Dispose, ресурс будет в итоге удален автоматически в результате сборки мусора.
Если выделение_ресурса задано как объявление_локальной_переменной, то типом объявления_локальной_переменной должен быть тип dynamic или тип, допускающий неявное преобразование в System.IDisposable. Если выделение_ресурса задано как выражение, то это должно быть выражение типа, допускающего неявное преобразование в System.IDisposable.
Локальные переменные, объявленные при выделении_ресурса, доступны только на чтение и должны включать инициализатор. Если внедренный оператор пытается изменить эти локальные переменные (путем присваивания или с помощью операторов ++ и ‑‑), получить их адрес или передать их как параметры ref или out, возникает ошибка времени компиляции.
Процесс оператора using состоит из трех частей: выделение ресурса, использование и удаление. Использование ресурса неявно включается в оператор try с предложением finally. Это предложение finally удаляет ресурс. Если выделяется ресурс null, метод Dispose не вызывается и исключение не генерируется. Если ресурс имеет тип dynamic, это означает, что он динамически преобразован путем неявного динамического преобразования (§6.1.8) к IDisposable в процессе выделения с целью обеспечения успешного преобразования перед использованием и удалением.
Оператор using в виде
using (ResourceType resource = expression) statement
может быть развернут тремя способами. Если ResourceType имеет необнуляемый тип значения, выражение имеет вид
В обоих случаях переменная resource доступна только для чтения во внедренном операторе, а переменная d недоступна и невидима для внедренного оператора.
В реализации разрешается выполнять реализацию определенного оператора using иным образом (например, для повышения быстродействия), при условии сохранения поведения, совместимого с вышеописанным развертыванием.
Оператор using в виде
using (expression) statement
может развертываться теми же тремя способами, но на этот раз в качестве ResourceType неявно принимается тип выражения expression, определяемый во время компиляции, а переменная resource недоступна и невидима для внедренного оператора.
Если выделение_ресурса задано в виде объявления_локальной_переменной, можно выделить несколько ресурсов данного типа. Оператор using в виде
в точности эквивалентен последовательности вложенных операторов using:
using (ResourceType r1 = e1) using (ResourceType r2 = e2) ... using (ResourceType rN = eN) statement
В следующем примере создается файл log.txt и в него записываются две строки текста. Затем тот же файл открывается для чтения, и содержащиеся в нем строки текста выводятся на консоль.
using System; using System.IO;
class Test { static void Main() { using (TextWriter w = File.CreateText("log.txt")) { w.WriteLine("This is line one"); w.WriteLine("This is line two"); }
using (TextReader r = File.OpenText("log.txt")) { string s; while ((s = r.ReadLine()) != null) { Console.WriteLine(s); }
} } }
Поскольку классы TextWriter и TextReader реализуют интерфейс IDisposable, в примере можно использовать оператор using для того, чтобы гарантировать корректное закрытие обрабатываемого файла после операций чтения или записи.
Yield
Оператор yield используется в блоке итератора (§8.2) для выдачи значения в объект перечислителя (§10.14.4) или в перечислимый объект итератора (§10.14.5), либо для сигнализации об окончании итерации.
оператор_yield: yield return выражение ; yield break ;
yield не является зарезервированным словом; оно приобретает особый смысл только тогда, когда стоит непосредственно перед ключевым словом return или break. В других контекстах yield может использоваться как идентификатор.
На использование оператора yield накладывается ряд ограничений.
· Использование оператора yield (в любой из двух форм) вне тела_метода, тела_оператора или тела_метода_доступа вызывает ошибку времени компиляции.
· Использование оператора yield (в любой из двух форм) внутри анонимной функции вызывает ошибку времени компиляции.
· Использование оператора yield (в любой из двух форм) в предложении finally оператора try вызывает ошибку времени компиляции.
· Использование оператора yield return в любом месте оператора try, содержащего предложения catch, вызывает ошибку времени компиляции.
В следующем примере демонстрируется несколько допустимых и недопустимых способов использования оператора yield.
delegate IEnumerable<int> D();
IEnumerator<int> GetEnumerator() { try { yield return 1; // Ok yield break; // Ok } finally { yield return 2; // Error, yield in finally yield break; // Error, yield in finally }
try { yield return 3; // Error, yield return in try...catch yield break; // Ok } catch { yield return 4; // Error, yield return in try...catch yield break; // Ok }
D d = delegate { yield return 5; // Error, yield in an anonymous function }; }
int MyMethod() { yield return 1; // Error, wrong return type for an iterator block }
Должно существовать неявное преобразование (§6.1) типа выражения оператора yield return в тип выдачи итератора (§10.14.3).
Оператор yield return выполняется следующим образом.
· Выражение, заданное в операторе, вычисляется, неявно преобразуется к типу yield и присваивается свойству Current объекта перечислителя;
· Выполнение блока итератора приостанавливается. Если оператор yield return находится внутри одного или более блоков try, их соответствующие блоки finally не выполняются в это время;
· Метод MoveNext объекта перечислителя возвращает true в вызвавшую его программу, тем самым указывая на успешный переход объекта перечислителя к следующему элементу.
Следующий вызов метода MoveNext объекта перечислителя возобновляет выполнение блока итератора с того места, где оно было приостановлено.
Оператор yield break выполняется следующим образом.
· Если оператор yield break входит в один или несколько блоков try, с которыми связаны соответствующие блоки finally, управление вначале передается в блок finally самого внутреннего оператора try. Если управление достигает конечной точки блока finally, после этого управление передается в блок finally следующего объемлющего оператора try. Этот процесс повторяется до тех пор, пока не будут выполнены все блоки finally всех объемлющих операторов try.
· Управление возвращается в метод, вызвавший блок итератора. Это либо метод MoveNext, либо метод Dispose объекта перечислителя.
Поскольку оператор yield осуществляет безусловную передачу управления в другое место, конечная точка оператора yield никогда не будет достижима.
9. Пространства имен
Программы на C# организованы с помощью пространств имен. Пространства имен используются как в качестве «внутренней» системы организации для программы, так и в качестве «внешней» системы организации — способа представления программных элементов, предоставляемых другим программам.
Директивы using (§9.4) служат для упрощения использования пространств имен.
9.1 Единицы компиляции
Единица_компиляции определяет общую структуру исходного файла. Единица компиляции состоит из 0 или более директив_using, за которыми следуют 0 или более глобальных_атрибутов, за которыми следуют 0 или более объявлений_членов_пространства_имен.
Программа на C# состоит из одной или более единиц компиляции, каждая из которых содержится в отдельном исходном файле. При компиляции программы на C# все единицы компиляции обрабатываются совместно. Таким образом, единицы компиляции могут зависеть друг от друга, возможно циклически.
Директивы_using единицы компиляции влияют на глобальные_атрибуты и объявления_членов_пространства_имен этой единицы компиляции, но не влияют на другие единицы компиляции.
Глобальные_атрибуты (§17) единицы компиляции разрешают спецификацию атрибутов для конечной сборки и модуля. Сборки и модули действуют как физические контейнеры для типов. Сборка может состоять из нескольких физически отдельных модулей.
Объявления_членов_пространства_имен каждой единицы компиляции программы размещают члены в одной области объявления, называемой глобальным пространством имен. Например:
Файл A.cs:
class A {}
Файл B.cs:
class B {}
Эти две единицы компиляции размещаются в одно глобальное пространство имен, в данном случае объявляя два класса с полными именами A и B. Поскольку эти две единицы компиляции размещаются в одну и ту же область объявлений, было бы ошибкой, если бы в каждой из них содержалось объявление члена с одинаковым именем.
9.2 Объявления пространства имен
Объявление_пространства_имен состоит из ключевого слова namespace, за которым следует имя и тело пространства имен, а затем точка с запятой (необязательно).
Объявление_пространства_имен может быть объявлением верхнего уровня в единице_компиляции или объявлением члена внутри другого объявления_пространства_имен. Если объявление_пространства_имен встречается как объявление верхнего уровня в единице_компиляции, это пространство имен становится членом глобального пространства имен. Если объявление_пространства_имен встречается внутри другого объявления_пространства_имен, внутреннее пространство имен становится членом внешнего пространства имен. В обоих случаях имя пространства имен долk