Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
16.1 Общие положения
Структуры похожи на классы, представляющие структуры данных, которые могут содержать элементы данных и члены функции. Однако, в отличие от классов, структуры являются типами значений и не требуют выделения кучи. Переменная типа struct
напрямую содержит данные struct
, тогда как переменная типа класса содержит ссылку на данные, причем последняя называется объектом.
Примечание. Структуры особенно полезны для небольших структур данных, имеющих семантику значений. Хорошими примерами структур можно считать комплексные числа, точки в системе координат или словари с парами ключ-значение. Ключом к этим структурам данных является то, что они имеют несколько элементов данных, которые не требуют использования семантики наследования или ссылки, а могут быть удобно реализованы семантикой значений, где назначение копирует значение вместо ссылки. конечная заметка
Как описано в §8.3.5, простые типы, предоставляемые C#, такие как int
, double
и bool
, на самом деле, являются всеми типами структур.
Объявления структур, раздел 16.2
16.2.1 Общие
Struct_declaration — это type_declaration (§14.7), которая объявляет новую структуру:
struct_declaration
: attributes? struct_modifier* 'ref'? 'partial'? 'struct'
identifier type_parameter_list? struct_interfaces?
type_parameter_constraints_clause* struct_body ';'?
;
Объявление структуры состоит из необязательного набора атрибутов (§22), за которым следует необязательный набор модификаторов структуры (§16.2.2), за которым следует необязательный модификатор (), за которым следует необязательный частичный модификатор (§15.2.7), за которым следует ключевое слово ref
и идентификатор, который именует структуру, за которым следует необязательная спецификация списка параметров типа (§15.2.3), за которой следует необязательная спецификация struct
(§16.2.5), за которой следует необязательная спецификация ограничений параметров типа (§15.2.5), за которой следует тело структуры (§16.2.6), за которым может следовать точка с запятой.
Объявление структуры не должно предоставлять type_parameter_constraints_clause, если только оно также не предоставляет type_parameter_list.
Объявление структуры, которое предоставляет type_parameter_list , является универсальным объявлением структуры. Кроме того, любая структура, вложенная в объявление универсального класса или универсальное объявление структуры, является универсальным объявлением структуры, так как аргументы типов для содержащего типа должны быть предоставлены для создания созданного типа (§8.4).
Объявление структуры, включающее ref
ключевое слово, не должно содержать часть "struct_interfaces".
Модификаторы структуры 16.2.2
Опционально struct_declaration может включать последовательность struct_modifier:
struct_modifier
: 'new'
| 'public'
| 'protected'
| 'internal'
| 'private'
| 'readonly'
| unsafe_modifier // unsafe code support
;
unsafe_modifier (§23.2) доступен только в небезопасном коде (§23).
Это ошибка компиляции, если один и тот же модификатор появляется несколько раз в объявлении структуры.
За исключением readonly
, модификаторы объявления структуры имеют то же значение, что и объявление класса (§15.2.2).
Модификатор readonly
указывает, что struct_declaration объявляет тип, экземпляры которого неизменяемы.
Структура только для чтения имеет следующие ограничения:
- Каждое из полей объекта также должно быть объявлено
readonly
. - Оно не должно объявлять какие-либо события, подобные полю (§15.8.2).
Когда экземпляр структуры только для чтения передается методу, она this
обрабатывается как входной аргумент/параметр, что запрещает запись в любые поля экземпляра (за исключением случаев, когда это делается конструкторами).
Модификатор ref 16.2.3
Модификатор ref
указывает, что struct_declaration объявляет тип, экземпляры которого выделяются в стеке выполнения. Эти типы называются типами структур ссылок . Модификатор ref
объявляет, что экземпляры могут содержать поля, подобные ссылкам, и не должны быть скопированы из безопасного контекста (§16.4.15). Правила определения безопасного контекста структуры ссылок описаны в разделе 16.4.15.
Это ошибка во время компиляции, если тип структуры ref используется в любом из следующих контекстов:
- В качестве типа элемента массива.
- Как объявленный тип поля класса или структуры, у которых нет
ref
модификатора. - Быть в коробке для
System.ValueType
илиSystem.Object
. - В качестве аргумента типа.
- Тип элемента кортежа.
- Асинхронный метод.
- Итератор.
- Преобразование из типа
ref struct
в типobject
или типSystem.ValueType
отсутствует. -
ref struct
Тип не должен быть объявлен для реализации любого интерфейса. - Метод экземпляра, объявленный в
object
илиSystem.ValueType
, но не переопределён в типеref struct
, не должен вызываться с объектом этогоref struct
типа. - Метод экземпляра
ref struct
типа не должен быть записан преобразованием группы методов в тип делегата. - Реф-структура не должна быть захвачена лямбда-выражением или локальной функцией.
Примечание:
ref struct
не должен объявлятьasync
методы экземпляра, а также использоватьyield return
илиyield break
инструкцию внутри метода экземпляра, потому что неявныйthis
параметр нельзя использовать в этих контекстах. конечная заметка
Эти ограничения гарантируют, что переменная ref struct
типа не ссылается на память стека, которая больше не допустима, или к переменным, которые больше не являются допустимыми.
16.2.4 Частичный модификатор
Модификатор partial
указывает, что этот struct_declaration является объявлением частичного типа. Несколько частичных объявлений структур с одинаковым именем в пределах пространства имен или объявления типа объединяются в одно объявление структуры, следуя правилам, указанным в §15.2.7.
Интерфейсы структур 16.2.5
Объявление структуры может включать спецификацию struct_interfaces , в этом случае структура, как сообщается, напрямую реализует указанные типы интерфейса. Для созданного типа структуры, включая вложенный тип, объявленный в объявлении универсального типа (§15.3.9.7), каждый реализованный тип интерфейса получается путем подстановки для каждого type_parameter в данном интерфейсе, соответствующего type_argument созданного типа.
struct_interfaces
: ':' interface_type_list
;
Обработка интерфейсов в нескольких частях объявления частичной структуры (§15.2.7) рассматривается далее в §15.2.4.3.
Реализации интерфейса рассматриваются далее в §18.6.
Тело структуры 16.2.6
Struct_body структуры определяет элементы структуры.
struct_body
: '{' struct_member_declaration* '}'
;
Элементы структуры 16.3
Члены структуры состоят из элементов, представленных его struct_member_declarationи членами, унаследованными от типа System.ValueType
.
struct_member_declaration
: constant_declaration
| field_declaration
| method_declaration
| property_declaration
| event_declaration
| indexer_declaration
| operator_declaration
| constructor_declaration
| static_constructor_declaration
| type_declaration
| fixed_size_buffer_declaration // unsafe code support
;
fixed_size_buffer_declaration (§23.8.2) доступен только в небезопасном коде (§23).
Примечание: Все виды class_member_declaration, кроме finalizer_declaration, также являются struct_member_declaration. конечная заметка
За исключением различий, указанных в §16.4, описания членов класса, предоставленных в §15.3 до §15.12, применяются к элементам структуры, а также.
Различия классов и структур 16.4
16.4.1 Общие
Структуры отличаются от классов несколькими важными способами:
- Структуры — это типы значений (§16.4.2).
- Все типы структур неявно наследуются от класса
System.ValueType
(§16.4.3). - Назначение переменной типа структуры создает копию присваиваемого значения (§16.4.4).
- Значение структуры по умолчанию — это значение, созданное путем установки всех полей в значение по умолчанию (§16.4.5).
- Операции боксинга и распаковки используются для преобразования типа структуры в конкретные ссылочные типы и обратно (§16.4.6).
- Смысл отличается в членах
this
структуры (§16.4.7). - Объявления полей экземпляра для структуры не допускаются включать инициализаторы переменных (§16.4.8).
- В структуре не разрешено объявлять конструктор экземпляра без параметров (§16.4.9).
- Структурам не разрешено объявлять финализаторы.
- Объявления событий, объявления свойств, методы доступа к свойствам, объявления индексатора и объявления методов могут иметь модификатор
readonly
, хотя это не разрешено для тех же типов элементов в классах.
Семантика значения 16.4.2
Структуры — это типы значений (§8.3) и имеют семантику значений. Классы, с другой стороны, являются ссылочными типами (§8.2) и, как говорят, имеют ссылочные семантики.
Переменная типа структуры напрямую содержит данные структуры, в то время как переменная типа класса содержит ссылку на объект, содержащий данные. Если структура B
содержит поле экземпляра типа A
, и A
является структурным типом, то ошибка времени компиляции возникает, если A
зависит от B
или типа, созданного на основе B
. Структура X
напрямую зависит от структурыY
, если X
содержит поле экземпляра типа Y
. Учитывая это определение, полный набор структур, от которых зависит данная структура, является транзитивным замыканием во взаимосвязи непосредственно зависит от.
Пример:
struct Node { int data; Node next; // error, Node directly depends on itself }
является ошибкой, так как
Node
содержит поле экземпляра собственного типа. Другой примерstruct A { B b; } struct B { C c; } struct C { A a; }
— это ошибка, так как каждый из типов
A
иB
C
зависит друг от друга.конец примера
Классы позволяют двум переменным ссылаться на один и тот же объект и, следовательно, могут влиять на объект, на который ссылается другая переменная. При использовании структур каждая переменная имеет собственную копию данных (кроме случаев, когда параметры передаются по ссылке), и операции с одной из них не могут повлиять на другую. Кроме того, за исключением случаев, когда явно допускается значение NULL (§8.3.12), нельзя использовать значения типа null
структуры.
Примечание. Если структуру содержит поле ссылочного типа, содержимое объекта, на который ссылается, может быть изменено другими операциями. Однако значение самого поля, т. е. объекта, на который он ссылается, невозможно изменить путем изменения другого значения структуры. конечная заметка
Пример. Учитывая следующее:
struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class A { static void Main() { Point a = new Point(10, 10); Point b = a; a.x = 100; Console.WriteLine(b.x); } }
выходные данные
10
. Назначениеa
кb
создает копию значения, и таким образомb
остается неизменным из-за назначенияa
к . Если быPoint
было объявлено как класс, выходные данные были бы100
, потому чтоa
иb
будут ссылаться на один и тот же объект.конец примера
Наследование 16.4.3
Все типы структур неявно наследуются от класса System.ValueType
, который, в свою очередь, наследует от класса object
. Объявление структуры может указывать список реализованных интерфейсов, но объявление структуры невозможно указать базовый класс.
Типы структур никогда не являются абстрактными и всегда неявно запечатаны. Поэтому модификаторы abstract
и sealed
не допускаются в объявлении структуры.
Так как наследование не поддерживается для структур, объявленная доступность элемента структуры не может быть protected
, private protected
или protected internal
.
Функции в структуре не могут быть абстрактными или виртуальными, и модификатор override
разрешается только для переопределения методов, унаследованных от System.ValueType
.
Назначение 16.4.4
Назначение переменной типа структуры создает копию присваиваемого значения. Это отличается от назначения переменной типа класса, которая копирует ссылку, но не объект, определенный ссылкой.
Подобно присваиванию, когда структура передается как параметр значения или возвращается в результате функции-члена, создается копия структуры. Структуру можно передать в функцию посредством параметра, передаваемого по ссылке.
Если свойство или индексатор структуры является целью назначения, выражение экземпляра, связанное со свойством или доступом индексатора, должно классифицироваться как переменная. Если выражение экземпляра классифицируется как значение, возникает ошибка во время компиляции. Это подробно описано в разделе 12.21.2.
Значения по умолчанию 16.4.5
Как описано в разделе 9.3, при создании переменных несколько типов переменных автоматически инициализированы в их значение по умолчанию. Для переменных типов классов и других ссылочных типов значение по умолчанию — это null
. Однако, так как структуры являются типами значений, которые не могут бытьnull
, значение по умолчанию структуры является значением, созданным путем установки всех полей типа значения по умолчанию и всех полей ссылочного типа.null
Пример: ссылка на структуру
Point
, объявленную выше, примерPoint[] a = new Point[100];
инициализирует каждый
Point
в массиве значением, полученным путем установки полейx
иy
в ноль.конец примера
Значение по умолчанию структуры соответствует значению, возвращаемого конструктором структуры по умолчанию (§8.3.3). В отличие от класса, в структуре не допускается объявлять конструктор экземпляра без параметров. Вместо этого каждая структура неявно имеет конструктор экземпляра без параметров, который всегда возвращает значение, которое приводит к настройке всех полей в значения по умолчанию.
Примечание. Структуры должны быть разработаны для рассмотрения состояния инициализации по умолчанию допустимого состояния. В примере
struct KeyValuePair { string key; string value; public KeyValuePair(string key, string value) { if (key == null || value == null) { throw new ArgumentException(); } this.key = key; this.value = value; } }
Определяемый пользователем конструктор экземпляра защищает
null
только от значений, где он вызывается явным образом. В случаях, когдаKeyValuePair
переменная подвергается инициализации значением по умолчанию, поляkey
иvalue
, а также структура, должны быть подготовлены для обработки этого состояния.конечная заметка
16.4.6 Бокс и распаковка
Значение типа класса можно преобразовать в тип object
или в тип интерфейса, реализуемый классом, просто рассматривая ссылку как другой тип во время компиляции. Аналогичным образом, значение типа object
или значения типа интерфейса можно преобразовать обратно в тип класса, не изменив ссылку (но, конечно, в данном случае требуется проверка типа во время выполнения).
Так как структуры не являются ссылочными типами, эти операции реализуются по-разному для типов структур. При преобразовании значения типа структуры в определенные ссылочные типы (как указано в §10.2.9), выполняется упаковка значения. Аналогичным образом, когда значение определенных ссылочных типов (как определено в §10.3.7) преобразуется обратно в тип структуры, выполняется операция распаковки. Ключевое отличие от одних и тех же операций с типами классов заключается в том, что упаковка и распаковка копируют значение структуры либо в боксовый экземпляр, либо из него.
Примечание. Таким образом, после операции упаковки или распаковки изменения, внесенные в распакованный
struct
, не находят отражения в упакованномstruct
. конечная заметка
Для получения дополнительных сведений об упаковке и распаковке см. в разделах §10.2.9 и §10.3.7.
Значение этого 16.4.7
Значение this
в структуре отличается от значения this
в классе, как описано в §12.8.14. Если тип структуры переопределяет виртуальный метод, унаследованный от System.ValueType
, (например, Equals
, GetHashCode
или ToString
), вызов виртуального метода через экземпляр типа структуры не приводит к упаковке. Это верно, даже если структура используется как параметр типа, и вызов происходит через экземпляр этого типа параметра.
Пример:
struct Counter { int value; public override string ToString() { value++; return value.ToString(); } } class Program { static void Test<T>() where T : new() { T x = new T(); Console.WriteLine(x.ToString()); Console.WriteLine(x.ToString()); Console.WriteLine(x.ToString()); } static void Main() => Test<Counter>(); }
Выходные данные программы:
1 2 3
Хотя это плохой стиль для
ToString
того чтобы иметь побочные эффекты, в примере показано, что бокс не произошел для трех вызововx.ToString()
.конец примера
Аналогичным образом, бокс никогда неявно происходит при доступе к члену в параметре ограниченного типа, когда член реализуется в типе значения. Например, предположим, что интерфейс ICounter
содержит метод Increment
, который можно использовать для изменения значения. Если ICounter
используется в качестве ограничения, реализация метода Increment
вызывается со ссылкой на переменную, на которой был вызван Increment
, никогда не на упакованной копии.
Пример:
interface ICounter { void Increment(); } struct Counter : ICounter { int value; public override string ToString() => value.ToString(); void ICounter.Increment() => value++; } class Program { static void Test<T>() where T : ICounter, new() { T x = new T(); Console.WriteLine(x); x.Increment(); // Modify x Console.WriteLine(x); ((ICounter)x).Increment(); // Modify boxed copy of x Console.WriteLine(x); } static void Main() => Test<Counter>(); }
Первый вызов
Increment
изменяет значение переменнойx
. Это не эквивалентно второму вызовуIncrement
, который изменяет значение в запакованной копииx
. Таким образом, выходные данные программы:0 1 1
конец примера
Инициализаторы полей 16.4.8
Как описано в §16.4.5, значение по умолчанию структуры состоит из значения, получаемого в результате установки всех полей типа значения в их значения по умолчанию и всех полей ссылочного типа в null
. Структура по этой причине не позволяет объявлению полей экземпляра включать инициализаторы переменных. Это ограничение применяется только к полям экземпляра. Статические поля структуры разрешены включать инициализаторы переменных.
Пример. Ниже приведено
struct Point { public int x = 1; // Error, initializer not permitted public int y = 1; // Error, initializer not permitted }
ошибка возникает, поскольку объявления полей экземпляра содержат инициализаторы переменных.
конец примера
field_declaration, объявленный непосредственно внутри struct_declaration с использованием struct_modifierreadonly
, должен иметь field_modifierreadonly
.
Конструкторы 16.4.9
В отличие от класса, в структуре не допускается объявлять конструктор экземпляра без параметров. Вместо этого каждая структура неявно имеет конструктор экземпляра без параметров, который всегда возвращает значение, полученное в результате установки всех полей типа значения в их значение по умолчанию и всех полей ссылочного типа в null
(§8.3.3). Структура может объявлять конструкторы экземпляров с параметрами.
Пример. Учитывая следующее:
struct Point { int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class A { static void Main() { Point p1 = new Point(); Point p2 = new Point(0, 0); } }
операторы создают
Point
, иx
иy
инициализируются до нуля.конец примера
Конструктор экземпляра структуры не может включать инициализатор конструктора формы base(
argument_list)
, где argument_list является необязательным.
Параметр this
конструктора экземпляра структуры соответствует выходному параметру типа структуры. Таким образом, this
должно быть однозначно назначено (§9.4) в каждом местоположении, где возвращается конструктор. Аналогичным образом, его нельзя читать (даже неявно) в теле конструктора перед определенным назначением.
Если конструктор экземпляра структуры задает инициализатор конструктора, этот инициализатор считается определенным назначением для этого, которое происходит до текста конструктора. Поэтому само тело не имеет требований к инициализации.
Пример. Рассмотрим реализацию конструктора экземпляра ниже:
struct Point { int x, y; public int X { set { x = value; } } public int Y { set { y = value; } } public Point(int x, int y) { X = x; // error, this is not yet definitely assigned Y = y; // error, this is not yet definitely assigned } }
Никакие члены функции экземпляра (включая наборы доступа для свойств
X
иY
) не могут вызываться до тех пор, пока не будут назначены все поля создаваемой структуры. Обратите внимание, что если быPoint
был классом, а не структурой, то реализация конструктора экземпляра была бы разрешена. Существует одно исключение, и это включает автоматически реализованные свойства (§15.7.4). Определенные правила назначения (§12.21.2) специально освобождают назначение для автоматического свойства типа структуры в конструкторе экземпляра этого типа структуры: такое назначение считается определенным назначением скрытого поля резервного поля автоматического свойства. Таким образом, допускается следующее:struct Point { public int X { get; set; } public int Y { get; set; } public Point(int x, int y) { X = x; // allowed, definitely assigns backing field Y = y; // allowed, definitely assigns backing field } }
конец примера
16.4.10 Статические конструкторы
Статические конструкторы для структур следуют большинству правил, что и для классов. Выполнение статического конструктора для типа структуры активируется первым из следующих событий, происходящих в домене приложения:
- Ссылается на статический член типа структуры.
- Вызывается явно объявленный конструктор типа структуры.
Примечание. Создание значений по умолчанию (§16.4.5) типов структур не активирует статический конструктор. (Примером этого является начальное значение элементов в массиве.) конечная заметка
Свойства 16.4.11
Property_declaration (§15.7.1) для свойства экземпляра в struct_declaration может содержать property_modifierreadonly
. Однако статичное свойство не должно содержать модификатор.
Во время компиляции возникает ошибка, если попытаться изменить состояние экземплярной переменной структуры через объявленное в этой структуре свойство только для чтения.
Это ошибка времени компиляции для автоматически реализуемого свойства с модификатором readonly
, которое также имеет аксессор set
.
Это ошибка на этапе компиляции, если автоматически реализованное свойство в readonly
структуре содержит аксессор set
.
Автоматически реализованное свойство, объявленное внутри readonly
структуры, не обязательно должно иметь readonly
модификатор, так как его get
аксессор неявно предполагается как только для чтения.
Ошибка времени компиляции возникает, если у свойства имеется модификатор readonly
, а также на любом из его аксессоров get
и set
.
Это ошибка во время компиляции для свойства, который должен иметь модификатор чтения на всех его методах доступа.
Примечание. Чтобы исправить ошибку, переместите модификатор из методов доступа к самому свойству. конечная заметка
Автоматически реализованные свойства (§15.7.4) используют скрытые поля резервной копии, которые доступны только для методов доступа к свойствам.
Примечание. Это ограничение доступа означает, что конструкторы в структурах, содержащих автоматически реализованные свойства, часто требуют явного инициализатора конструктора, даже если в остальных случаях он им не нужен. Это необходимо для выполнения требования, чтобы все поля были определённо назначены до вызова любого члена функции или возврата конструктора. конечная заметка
Методы 16.4.12
method_declaration (§15.6.1) для метода экземпляра в struct_declaration может содержать method_modifierreadonly
. Однако статический метод не должен содержать этот модификатор.
Это ошибка во время компиляции, которая пытается изменить состояние переменной структуры экземпляра с помощью метода чтения, объявленного в этой структуре.
Хотя метод readonly может вызывать одноуровневый метод, нечитающийся или свойство или индексатор доступа, это приводит к созданию неявной копии this
в качестве оборонительной меры.
Метод readonly может вызывать одноуровневое свойство или метод доступа с набором индексатора, который доступен для чтения. Если метод доступа члена-сиблинга не является явно или неявно только для чтения, возникает ошибка компиляции.
Все method_declaration частичного метода должны иметь readonly
модификатор, или ни один из них не должен иметь его.
Индексаторы 16.4.13
Indexer_declaration (§15.9) для индексатора экземпляров в struct_declaration может содержать indexer_modifierreadonly
.
Это ошибка времени компиляции, возникающая при попытке изменить состояние переменной структуры экземпляра с помощью индексатора с модификатором readonly, объявленного в этой структуре.
Это ошибка компиляции, если использовать модификатор readonly
для самого индексатора, а также на любом из его get
или set
аксессоров.
Индексатор с модификатором readonly во всех своих аксессорах вызывает ошибку времени компиляции.
Примечание. Чтобы исправить ошибку, переместите модификатор из методов доступа к самому индексатору. конечная заметка
16.4.14 События
Объявление события (§15.8.1) для экземпляра, несвязанного с полем, в объявлении структуры может содержать модификатор событияreadonly
. Однако статическое событие не должно содержать этот модификатор.
Ограничение контекста безопасности 16.4.15
16.4.15.1 General
Во время компиляции каждое выражение связано с контекстом, в котором можно безопасно получить доступ к этому экземпляру и всем его полям, его безопасный контекст. Безопасный контекст — это контекст, включающий выражение, в который значение может безопасно передаваться.
Любое выражение, тип на этапе компиляции которого не является структурой ссылок, имеет безопасный контекст вызова.
Выражение default
любого типа имеет безопасный контекст в вызывающей среде.
Для любого выражения, отличного от стандартного, тип которого на этапе компиляции является ref struct, имеет безопасный контекст, который определяется следующими разделами.
Записи безопасного контекста фиксируют, в какой контекст может быть скопировано значение. Учитывая присваивание из выражения E1
с безопасным контекстом S1
, в выражение E2
с безопасным контекстом S2
, это будет ошибкой, если S2
окажется более широким контекстом, чем S1
.
Существует три разных значения безопасного контекста, такие же, как значения ref-safe-context, определенные для ссылочных переменных (§9.7.2): объявление-блок, член-функция и вызывающий контекст. Безопасный контекст выражения ограничивает его использование следующим образом:
- Для инструкции
return e1
return безопасный контекстe1
должен быть вызывающим контекстом. - Для назначения
e1 = e2
безопасный контекстe2
должен быть по крайней мере таким же широким, как безопасный контекстe1
.
Для вызова метода, если существует аргумент ref
или out
типа ref struct
(включая приемник, если тип не readonly
), с безопасным контекстом S1
, то ни один аргумент (включая приемник) не может иметь более узкий безопасный контекст, чем S1
.
Безопасный контекст параметра 16.4.15.2
Параметр типа ref struct, включая this
параметр метода экземпляра, имеет контекст безопасности контекста вызова.
16.4.15.3 Безопасный контекст локальной переменной
Локальная переменная структуры типа ref имеет безопасный контекст следующим образом:
- Если переменная является переменной
foreach
итерации цикла, то безопасный контекст переменной совпадает с безопасным контекстомforeach
выражения цикла. - В противном случае, если объявление переменной имеет инициализатор, безопасный контекст переменной совпадает с безопасным контекстом этого инициализатора.
- В противном случае переменная в точке объявления является неинициализированной и находится в безопасном контексте контекста вызывающего.
Безопасный контекст поля 16.4.15.4
Ссылка на поле e.F
, где тип F
является типом структуры ref, имеет контекст безопасности, который совпадает с контекстом безопасности e
.
Операторы 16.4.15.5
Приложение определяемого пользователем оператора рассматривается как вызов метода (§16.4.15.6).
Для оператора, который дает значение, например e1 + e2
или c ? e1 : e2
, безопасный контекст результата является самым узким контекстом среди безопасных контекстов операндов оператора. В результате для унарного оператора, который дает значение, например +e
, безопасный контекст результата является безопасным контекстом операнда.
Примечание. Первый операнд условного оператора — это
bool
, поэтому его безопасный контекст — контекст вызывающего. Из этого следует, что результирующий безопасный контекст является самым узким безопасным контекстом второго и третьего операнда. конечная заметка
Метод и вызов свойств 16.4.15.6
Значение, полученное из вызова метода e1.M(e2, ...)
или вызова свойства e.P
, имеет безопасный контекст наименьшего из следующих контекстов:
- вызывающий контекст.
- Безопасный контекст всех выражений аргументов (включая получателя).
Вызов свойства (либо get
или set
) рассматривается как вызов метода основополагающего метода согласно приведенным выше правилам.
16.4.15.7 stackalloc
Результат выражения stackalloc имеет безопасный контекст элемента-функции.
Вызовы конструктора 16.4.15.8
new
Выражение, вызывающее конструктор, подчиняется тем же правилам, что и вызов метода, возвращающего создаваемый тип.
Кроме того, безопасный контекст является наименьшим из безопасных контекстов всех аргументов и операндов всех выражений инициализатора объектов, если рекурсивно присутствует какой-либо инициализатор.
Примечание. Эти правила полагаются на
Span<T>
отсутствие конструктора следующей формы:public Span<T>(ref T p)
Такой конструктор делает экземпляры
Span<T>
, используемые в качестве полей, неотличимыми от поляref
. Правила безопасности, описанные в этом документе, зависят отref
полей, которые не имеют допустимой конструкции в C# или .NET. конечная заметка
ECMA C# draft specification