ВыраженияExpressions

Выражение — это последовательность операторов и операндов.An expression is a sequence of operators and operands. В этой главе описывается синтаксис, порядок вычисления операндов и операторов, а также смысл выражений.This chapter defines the syntax, order of evaluation of operands and operators, and meaning of expressions.

Классификации выраженийExpression classifications

Выражение может иметь один из следующих типов.An expression is classified as one of the following:

  • Значение.A value. У каждого значения есть связанный с ним тип.Every value has an associated type.
  • Переменная.A variable. Каждая переменная имеет связанный тип, а именно объявленный тип переменной.Every variable has an associated type, namely the declared type of the variable.
  • Пространство имен.A namespace. Выражение с этой классификацией может появляться только в левой части member_access (доступ к членам).An expression with this classification can only appear as the left hand side of a member_access (Member access). В любом другом контексте выражение классифицируется как пространство имен вызывает ошибку времени компиляции.In any other context, an expression classified as a namespace causes a compile-time error.
  • Тип.A type. Выражение с этой классификацией может появляться только в левой части member_access (доступ к членам), или в качестве операнда для as оператор (оператор As ), is оператор (является оператором), или typeof оператор (оператор typeof).An expression with this classification can only appear as the left hand side of a member_access (Member access), or as an operand for the as operator (The as operator), the is operator (The is operator), or the typeof operator (The typeof operator). В любом другом контексте выражение классифицируется как тип вызывает ошибку времени компиляции.In any other context, an expression classified as a type causes a compile-time error.
  • Метод группу, которая представляет собой набор перегруженных методов, полученный в результате поиска члена (поиск члена).A method group, which is a set of overloaded methods resulting from a member lookup (Member lookup). Группа методов может иметь связанное выражение экземпляра и связанный список аргументов типа.A method group may have an associated instance expression and an associated type argument list. При вызове метода экземпляра, результат вычисления выражения экземпляра становится экземпляра, представленного this (такой доступ).When an instance method is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access). Группа метод invocation_expression (выражения вызова), delegate_creation_expression (делегировать создание выражения) и в качестве левой части операций является оператором и может быть неявно преобразован в совместимого типа делегата (преобразования групп методов).A method group is permitted in an invocation_expression (Invocation expressions) , a delegate_creation_expression (Delegate creation expressions) and as the left hand side of an is operator, and can be implicitly converted to a compatible delegate type (Method group conversions). В любом другом контексте выражение классифицировано как группа метод вызывает ошибку времени компиляции.In any other context, an expression classified as a method group causes a compile-time error.
  • Литерал null.A null literal. Выражение с этой классификацией может неявно преобразовываться в ссылочный тип или тип, допускающий значение NULL.An expression with this classification can be implicitly converted to a reference type or nullable type.
  • Анонимная функция.An anonymous function. Выражение с этой классификацией может неявно преобразовываться в совместимый тип делегата или тип дерева выражения.An expression with this classification can be implicitly converted to a compatible delegate type or expression tree type.
  • Доступ к свойству.A property access. Каждый доступ к свойству имеет связанный тип, а именно тип свойства.Every property access has an associated type, namely the type of the property. Кроме того доступ к свойству может быть связанным выражением экземпляра.Furthermore, a property access may have an associated instance expression. Если метод доступа ( get или set блок) экземпляра вызывается доступ к свойству, результат вычисления выражения экземпляра становится экземпляра, представленного this (такой доступ).When an accessor (the get or set block) of an instance property access is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access).
  • Доступ к событию.An event access. Каждого доступа к событию имеет связанный тип, а именно тип события.Every event access has an associated type, namely the type of the event. Кроме того доступ к событию может быть связанным выражением экземпляра.Furthermore, an event access may have an associated instance expression. Доступ к событию может выглядеть как левый операнд += и -= операторы (назначения события).An event access may appear as the left hand operand of the += and -= operators (Event assignment). В любом другом контексте выражение доступа к событию вызывает ошибку времени компиляции.In any other context, an expression classified as an event access causes a compile-time error.
  • Доступ к индексатору.An indexer access. Каждого доступа к индексатору имеет связанный тип, а именно тип элемента индексатора.Every indexer access has an associated type, namely the element type of the indexer. Кроме того доступ к индексатору имеет связанное выражение экземпляра и связанный список аргументов.Furthermore, an indexer access has an associated instance expression and an associated argument list. Если метод доступа ( get или set блок) индексатора вызывается доступ, результат вычисления выражения экземпляра становится экземпляра, представленного this (такой доступ) и результат вычисления списка аргументов становится списком параметров вызова.When an accessor (the get or set block) of an indexer access is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access), and the result of evaluating the argument list becomes the parameter list of the invocation.
  • никаких действий.Nothing. Это происходит, если выражение является вызов метода с типом возвращаемого значения void.This occurs when the expression is an invocation of a method with a return type of void. Выражение классифицируется как допустимо только в контексте statement_expression (операторы выражений).An expression classified as nothing is only valid in the context of a statement_expression (Expression statements).

Результат выражения никогда не является пространство имен, тип, группу методов или доступа к событиям.The final result of an expression is never a namespace, type, method group, or event access. Скорее как указано выше, эти категории выражений представляют собой промежуточные конструкции, которые допускаются только в определенных контекстах.Rather, as noted above, these categories of expressions are intermediate constructs that are only permitted in certain contexts.

Доступ к свойству или индексатору всегда менять свой тип значение при вызове метод доступа get или метода доступа set.A property access or indexer access is always reclassified as a value by performing an invocation of the get accessor or the set accessor. Определенный метод доступа определяется в контексте доступа свойства или индексатора: Если доступ является целевым объектом назначения, метода доступа set вызывается для присвоения нового значения (простое присваивание).The particular accessor is determined by the context of the property or indexer access: If the access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). В противном случае метод доступа get вызывается для получения текущего значения (значения выражений).Otherwise, the get accessor is invoked to obtain the current value (Values of expressions).

Значения выраженийValues of expressions

Большинство конструкций, в которых участвует выражение, это требует, чтобы выражение обозначало значение.Most of the constructs that involve an expression ultimately require the expression to denote a value. В таких случаях если фактическое выражение обозначает пространство имен, типом, группой методов или nothing, возникает ошибка времени компиляции.In such cases, if the actual expression denotes a namespace, a type, a method group, or nothing, a compile-time error occurs. Тем не менее если выражение обозначает доступ к свойству, индексатору или переменной, значение свойства, индексатора или переменной неявно заменяется:However, if the expression denotes a property access, an indexer access, or a variable, the value of the property, indexer, or variable is implicitly substituted:

  • Значение переменной является просто значение, хранящихся в расположении, указанном переменной.The value of a variable is simply the value currently stored in the storage location identified by the variable. Переменная должна быть считается определенно присвоенной (определенного присваивания) перед его значение можно получить, или в противном случае возникает ошибка времени компиляции.A variable must be considered definitely assigned (Definite assignment) before its value can be obtained, or otherwise a compile-time error occurs.
  • Значение выражения доступа к свойству получается путем вызова метод доступа get свойства.The value of a property access expression is obtained by invoking the get accessor of the property. Если свойство не имеет метод доступа get, возникает ошибка времени компиляции.If the property has no get accessor, a compile-time error occurs. В противном случае вызов функции-члена (Проверка динамического разрешения перегрузки во время компиляции) выполняется, и результат вызова становится значением выражения доступа к свойству.Otherwise, a function member invocation (Compile-time checking of dynamic overload resolution) is performed, and the result of the invocation becomes the value of the property access expression.
  • Значение выражения доступа индексатора получается путем вызова метод доступа get индексатора.The value of an indexer access expression is obtained by invoking the get accessor of the indexer. Если не имеет индексатора метод доступа get, возникает ошибка времени компиляции.If the indexer has no get accessor, a compile-time error occurs. В противном случае вызов функции-члена (Проверка динамического разрешения перегрузки во время компиляции) выполняется с аргументом списка, связанное с выражением доступа индексатора, а результат вызова становится значение выражения доступа индексатора.Otherwise, a function member invocation (Compile-time checking of dynamic overload resolution) is performed with the argument list associated with the indexer access expression, and the result of the invocation becomes the value of the indexer access expression.

Статическая и динамическая привязкаStatic and Dynamic Binding

Процесс определения значения операцию на основании типа или значения составляющих выражений (аргументы, операнды, приемники) часто называется привязки.The process of determining the meaning of an operation based on the type or value of constituent expressions (arguments, operands, receivers) is often referred to as binding. Для экземпляра значение вызова метода определяется на основе приемника и аргументы типа.For instance the meaning of a method call is determined based on the type of the receiver and arguments. Значение оператора определяется исходя из своих операндов типа.The meaning of an operator is determined based on the type of its operands.

В C#, значение операции обычно определяется во время компиляции, исходя из его составляющих выражений типа во время компиляции.In C# the meaning of an operation is usually determined at compile-time, based on the compile-time type of its constituent expressions. Аналогично Если выражение содержит ошибку, ошибка обнаружена и компилятор сообщает.Likewise, if an expression contains an error, the error is detected and reported by the compiler. Этот подход известен как статической привязки.This approach is known as static binding.

Тем не менее если выражение является динамическим выражением (т. е. имеет тип dynamic) это означает, что любой привязки, который участвует в должны быть основаны на типе времени выполнения (т. е. фактический тип объекта, он обозначает во время выполнения) вместо того, чтобы на тип При компиляции.However, if an expression is a dynamic expression (i.e. has the type dynamic) this indicates that any binding that it participates in should be based on its run-time type (i.e. the actual type of the object it denotes at run-time) rather than the type it has at compile-time. Таким образом привязку такая операция откладывается до времени, которого операция, выполняемая во время выполнения программы.The binding of such an operation is therefore deferred until the time where the operation is to be executed during the running of the program. Это называется динамической привязки.This is referred to as dynamic binding.

Если операция является динамическим, практически не проверка выполняется компилятором.When an operation is dynamically bound, little or no checking is performed by the compiler. Вместо этого при сбое привязки времени выполнения, ошибки выводятся как исключения во время выполнения.Instead if the run-time binding fails, errors are reported as exceptions at run-time.

Следующие операции в C# регулируются привязки:The following operations in C# are subject to binding:

  • Доступ к членам: e.MMember access: e.M
  • Вызов метода: e.M(e1, ..., eN)Method invocation: e.M(e1, ..., eN)
  • Вызов делегата:e(e1, ..., eN)Delegate invocation:e(e1, ..., eN)
  • Доступ к элементам: e[e1, ..., eN]Element access: e[e1, ..., eN]
  • Создание объекта: new C(e1, ..., eN)Object creation: new C(e1, ..., eN)
  • Перегрузка унарных операторов: +, -, !, ~, ++, --, true, falseOverloaded unary operators: +, -, !, ~, ++, --, true, false
  • Перегруженные бинарные операторы: +, -, *, /, %, &, &&, |, ||, ??, ^, << , >>, ==,!=, >, <, >=, <=Overloaded binary operators: +, -, *, /, %, &, &&, |, ||, ??, ^, <<, >>, ==,!=, >, <, >=, <=
  • Операторы присваивания: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=Assignment operators: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
  • Явные и неявные преобразованияImplicit and explicit conversions

При использовании динамические выражения, C# по умолчанию статической привязки, это означает, что в процесс выбора используются типы составных выражений во время компиляции.When no dynamic expressions are involved, C# defaults to static binding, which means that the compile-time types of constituent expressions are used in the selection process. Тем не менее если одна из составляющих выражений в приведенных выше операций динамического выражения, операция привязывается динамически.However, when one of the constituent expressions in the operations listed above is a dynamic expression, the operation is instead dynamically bound.

Во время привязкиBinding-time

Статическая привязка выполняется во время компиляции, а динамическая привязка происходит во время выполнения.Static binding takes place at compile-time, whereas dynamic binding takes place at run-time. В следующих разделах термин времени привязки ссылается на время компиляции или выполнения, в зависимости от того, когда выполняется привязка.In the following sections, the term binding-time refers to either compile-time or run-time, depending on when the binding takes place.

Следующий пример иллюстрирует уведомления статическая и динамическая привязка и во время привязки:The following example illustrates the notions of static and dynamic binding and of binding-time:

object  o = 5;
dynamic d = 5;

Console.WriteLine(5);  // static  binding to Console.WriteLine(int)
Console.WriteLine(o);  // static  binding to Console.WriteLine(object)
Console.WriteLine(d);  // dynamic binding to Console.WriteLine(int)

Первые два вызова являются статическими: перегрузка Console.WriteLine выбирается на основе типа времени компиляции аргумента.The first two calls are statically bound: the overload of Console.WriteLine is picked based on the compile-time type of their argument. Таким образом время привязки во время компиляции.Thus, the binding-time is compile-time.

Третий вызов является динамическим: перегрузка Console.WriteLine выбирается на основе типа среды выполнения своего аргумента.The third call is dynamically bound: the overload of Console.WriteLine is picked based on the run-time type of its argument. Это происходит потому, что аргумент является динамическим выражением--его тип времени компиляции — dynamic.This happens because the argument is a dynamic expression -- its compile-time type is dynamic. Таким образом время привязки третьего вызова во время выполнения.Thus, the binding-time for the third call is run-time.

динамическая привязка;Dynamic binding

Динамическая привязка предназначена для разрешить программы на C# для взаимодействия с динамические объекты, т. е. система типов объектов, которые не следовать нормальным правилам C#.The purpose of dynamic binding is to allow C# programs to interact with dynamic objects, i.e. objects that do not follow the normal rules of the C# type system. Динамические объекты могут быть объекты из других языков программирования с системами различных типов, или они могут быть объекты, которые запрограммированы для реализации собственной семантики привязки для различных операций.Dynamic objects may be objects from other programming languages with different types systems, or they may be objects that are programmatically setup to implement their own binding semantics for different operations.

Механизм, по которому динамический объект реализует собственную семантику это определяется реализацией.The mechanism by which a dynamic object implements its own semantics is implementation defined. --Снова определяется реализацией--данный интерфейс реализуется динамическими объектами для указания для C# времени выполнения, что они имеют особой семантики.A given interface -- again implementation defined -- is implemented by dynamic objects to signal to the C# run-time that they have special semantics. Таким образом каждый раз, когда операции на динамический объект динамически связываются, собственную семантику привязки, а не те, C#, как указано в этом документе, перехватить.Thus, whenever operations on a dynamic object are dynamically bound, their own binding semantics, rather than those of C# as specified in this document, take over.

Хотя динамической привязки предназначена для того, чтобы разрешить взаимодействие с динамическими объектами, C# позволяет динамической привязки для всех объектов ли они являются динамическими, или нет.While the purpose of dynamic binding is to allow interoperation with dynamic objects, C# allows dynamic binding on all objects, whether they are dynamic or not. Это обеспечивает более тесную интеграцию динамические объекты, как результаты выполнения операций над их сами по себе не может быть динамических объектов, но по-прежнему имеют тип неизвестного программисту во время компиляции.This allows for a smoother integration of dynamic objects, as the results of operations on them may not themselves be dynamic objects, but are still of a type unknown to the programmer at compile-time. Также динамической привязки может помочь устранить подверженного ошибкам кода на основе отражения, даже в том случае, если не участвующие объекты динамических объектов.Also dynamic binding can help eliminate error-prone reflection-based code even when no objects involved are dynamic objects.

В следующих разделах для каждой конструкции в языке точно при динамической привязки применяется, что компиляция проверки во время--если любой--применяется, и какие компиляции результат и выражение классификацией.The following sections describe for each construct in the language exactly when dynamic binding is applied, what compile time checking -- if any -- is applied, and what the compile-time result and expression classification is.

Типы составных выраженийTypes of constituent expressions

Если операция статически привязку, тип составного выражения (например, получатель, аргумент, индекса или операнд) всегда считается типов во время компиляции этого выражения.When an operation is statically bound, the type of a constituent expression (e.g. a receiver, an argument, an index or an operand) is always considered to be the compile-time type of that expression.

Если операция является динамическим, тип составного выражения определяется по-разному в зависимости от типа во время компиляции составного выражения:When an operation is dynamically bound, the type of a constituent expression is determined in different ways depending on the compile-time type of the constituent expression:

  • Составное выражение типов во время компиляции dynamic должно иметь тип фактического значения, выражение принимает значение во время выполненияA constituent expression of compile-time type dynamic is considered to have the type of the actual value that the expression evaluates to at runtime
  • Считается, что составное выражение, тип которого во время компиляции является параметром типа является тип, который параметр типа привязан к во время выполненияA constituent expression whose compile-time type is a type parameter is considered to have the type which the type parameter is bound to at runtime
  • В противном случае составное выражение считается тип времени компиляции.Otherwise the constituent expression is considered to have its compile-time type.

ОператорыOperators

Выражения, построенные на основе операндов и операторы.Expressions are constructed from operands and operators. Операторы в выражении указывают, какие действия нужно применить к операндам.The operators of an expression indicate which operations to apply to the operands. Примеры операторов: +, -, *, / и new.Examples of operators include +, -, *, /, and new. Операндами могут являться литералы, поля, локальные переменные, выражения и т. п.Examples of operands include literals, fields, local variables, and expressions.

Существует три типа операторов.There are three kinds of operators:

  • Унарные операторы.Unary operators. Унарные операторы принимают один операнд и используют префиксной (такие как --x) или почтовый индекс (такие как x++).The unary operators take one operand and use either prefix notation (such as --x) or postfix notation (such as x++).
  • Бинарные операторы.Binary operators. Бинарные операторы используются два операнда, и в виде инфикса (такие как x + y).The binary operators take two operands and all use infix notation (such as x + y).
  • троичный оператор.Ternary operator. Только один Тернарный оператор ?:, существует; он принимает три операнда и используется инфиксная запись (c ? x : y).Only one ternary operator, ?:, exists; it takes three operands and uses infix notation (c ? x : y).

Порядок вычисления операторов в выражении определяется приоритет и ассоциативность операторов (приоритет и ассоциативность операторов) .The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators (Operator precedence and associativity).

Операнды в выражении вычисляются слева направо.Operands in an expression are evaluated from left to right. Например, в F(i) + G(i++) * H(i), метод F вызывается с помощью старое значение i, затем метод G вызывается с старое значение iи, наконец, метод H вызывается с новым значением i.For example, in F(i) + G(i++) * H(i), method F is called using the old value of i, then method G is called with the old value of i, and, finally, method H is called with the new value of i. Это отдельно от и не связана с приоритетом операторов.This is separate from and unrelated to operator precedence.

Некоторые операторы могут быть перегружены.Certain operators can be overloaded. Перегрузка операторов позволяет создать определяемый пользователем оператор реализацию для операций там, где один или оба операнда имеют определяемый пользователем тип класса или структуры (перегрузка операторов).Operator overloading permits user-defined operator implementations to be specified for operations where one or both of the operands are of a user-defined class or struct type (Operator overloading).

Приоритет и ассоциативность операторовOperator precedence and associativity

Если выражение содержит несколько операторов, порядок вычисления этих операторов определяется их приоритетом.When an expression contains multiple operators, the precedence of the operators controls the order in which the individual operators are evaluated. Например, выражение x + y * z вычисляется как x + (y * z) поскольку * оператор имеет более высокий приоритет, чем двоичные + оператор.For example, the expression x + y * z is evaluated as x + (y * z) because the * operator has higher precedence than the binary + operator. Приоритет оператора устанавливается для определения его связанные грамматики производства.The precedence of an operator is established by the definition of its associated grammar production. Например additive_expression состоит из последовательности multiplicative_expressions, разделенных точкой + или - операторы, тем самым предоставляя + и - операторы имеют более низкий приоритет, чем *, /, и % операторы.For example, an additive_expression consists of a sequence of multiplicative_expressions separated by + or - operators, thus giving the + and - operators lower precedence than the *, /, and % operators.

В следующей таблице перечислены все операторы в порядке от самого высокого до самого низкого:The following table summarizes all operators in order of precedence from highest to lowest:

РазделSection КатегорияCategory ИнструкцииOperators
Первичные выраженияPrimary expressions ПервичныйPrimary x.y f(x) a[x] x++ x-- new typeof default checked unchecked delegatex.y f(x) a[x] x++ x-- new typeof default checked unchecked delegate
Унарные операторыUnary operators УнарныйUnary + - ! ~ ++x --x (T)x+ - ! ~ ++x --x (T)x
Арифметические операторыArithmetic operators МультипликативныйMultiplicative * / %* / %
Арифметические операторыArithmetic operators АддитивныйAdditive + -+ -
Операторы сдвигаShift operators СдвигShift << >><< >>
Реляционные операторы и операторы тестирования типаRelational and type-testing operators Тестирования типа и относительныеRelational and type testing < > <= >= is as< > <= >= is as
Реляционные операторы и операторы тестирования типаRelational and type-testing operators РавенствоEquality == !=== !=
Логические операторыLogical operators Логическое ИLogical AND &
Логические операторыLogical operators Логическое исключающее ИЛИLogical XOR ^
Логические операторыLogical operators Логическое ИЛИLogical OR |
Условные логические операторыConditional logical operators Условное ИConditional AND &&
Условные логические операторыConditional logical operators Условное ИЛИConditional OR ||
Оператор объединения со значением NULLThe null coalescing operator Объединение со значением NULLNull coalescing ??
Условный операторConditional operator УсловиеConditional ?:
Операторы присваивания, выражения анонимных функцийAssignment operators, Anonymous function expressions Присвоение и лямбда-выраженияAssignment and lambda expression = *= /= %= += -= <<= >>= &= ^= |= =>= *= /= %= += -= <<= >>= &= ^= |= =>

Если операнд располагается между двумя операторами с одинаковым приоритетом, ассоциативностью операторов управляет порядком, в котором выполняются операции:When an operand occurs between two operators with the same precedence, the associativity of the operators controls the order in which the operations are performed:

  • Кроме операторы присваивания и оператор объединения со значением null, все бинарные операторы имеют левую ассоциативность, это означает, что операции выполняются слева направо.Except for the assignment operators and the null coalescing operator, all binary operators are left-associative, meaning that operations are performed from left to right. Например, выражение x + y + z вычисляется как (x + y) + z.For example, x + y + z is evaluated as (x + y) + z.
  • Операторы присваивания, оператор объединения со значением null и условный оператор (?:) являются правоассоциативным, это означает, что операции выполняются слева направо.The assignment operators, the null coalescing operator and the conditional operator (?:) are right-associative, meaning that operations are performed from right to left. Например, выражение x = y = z вычисляется как x = (y = z).For example, x = y = z is evaluated as x = (y = z).

Приоритет и ассоциативность операторов можно изменять, используя скобки.Precedence and associativity can be controlled using parentheses. Например, в выражении x + y * z сначала y умножается на z, а результат прибавляется к x, а в выражении (x + y) * z сначала суммируются x и y, а результат умножается на z.For example, x + y * z first multiplies y by z and then adds the result to x, but (x + y) * z first adds x and y and then multiplies the result by z.

Перегрузка операторовOperator overloading

Все унарные и бинарные операторы имеют предварительно определенные реализации, которые автоматически становятся доступными в любом выражении.All unary and binary operators have predefined implementations that are automatically available in any expression. В дополнение к стандартным реализациям определенные пользователем реализации могут быть введены, включив operator объявления в классы и структуры (операторы).In addition to the predefined implementations, user-defined implementations can be introduced by including operator declarations in classes and structs (Operators). Реализации определяемых пользователем операторов всегда имеют приоритет над реализации стандартных операторов: Только если не применимо определяемого пользователем оператора существует считаться реализации стандартных операторов, как описано в разделе разрешение перегрузки унарного оператора и перегрузку бинарного оператора разрешение.User-defined operator implementations always take precedence over predefined operator implementations: Only when no applicable user-defined operator implementations exist will the predefined operator implementations be considered, as described in Unary operator overload resolution and Binary operator overload resolution.

Перегружаемые унарные операторы являются:The overloadable unary operators are:

+   -   !   ~   ++   --   true   false

Несмотря на то что true и false явным образом не используются в выражениях (и поэтому не включены в таблице приоритетов в приоритет и ассоциативность операторов), они считаются операторами, поскольку они являются вызывается в нескольких контекстах выражения: логические выражения (логических выражений) и выражения, включающие условия (условный оператор) и логического условия операторы (условные логические операторы).Although true and false are not used explicitly in expressions (and therefore are not included in the precedence table in Operator precedence and associativity), they are considered operators because they are invoked in several expression contexts: boolean expressions (Boolean expressions) and expressions involving the conditional (Conditional operator), and conditional logical operators (Conditional logical operators).

Перегружаемые бинарные операторы являются:The overloadable binary operators are:

+   -   *   /   %   &   |   ^   <<   >>   ==   !=   >   <   >=   <=

Только перечисленные выше операторы могут быть перегружены.Only the operators listed above can be overloaded. В частности, это невозможно перегрузить доступ к членам, вызов метода или =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, default, as, и is операторы.In particular, it is not possible to overload member access, method invocation, or the =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, default, as, and is operators.

При перегрузке бинарного оператора соответствующий оператор присвоения (если таковой имеется) также неявно перегружается.When a binary operator is overloaded, the corresponding assignment operator, if any, is also implicitly overloaded. Например, при перегрузке оператора * также является перегрузкой оператора *=.For example, an overload of operator * is also an overload of operator *=. Это описано далее в Составное присваивание.This is described further in Compound assignment. Обратите внимание, что сам оператор присваивания (=) не могут быть перегружены.Note that the assignment operator itself (=) cannot be overloaded. Назначения всегда выполняет простое побитовое копирование значения в переменную.An assignment always performs a simple bit-wise copy of a value into a variable.

Операций приведения типов, таких как (T)x, являются перегруженными, предоставляя заданные пользователем преобразования (заданные пользователем преобразования).Cast operations, such as (T)x, are overloaded by providing user-defined conversions (User-defined conversions).

Доступ к элементу, такие как a[x], не считается перегружаемый оператор.Element access, such as a[x], is not considered an overloadable operator. Вместо этого пользовательские индексирования поддерживается с помощью индексаторов (индексаторы).Instead, user-defined indexing is supported through indexers (Indexers).

В выражениях операторы, указываются нотация оператора, а в объявлениях, операторы, указываются функциональная нотация.In expressions, operators are referenced using operator notation, and in declarations, operators are referenced using functional notation. В следующей таблице показана связь между оператором и записью для унарные и бинарные операторы.The following table shows the relationship between operator and functional notations for unary and binary operators. В первой записи op обозначает перегружаемый унарный оператор, префикс.In the first entry, op denotes any overloadable unary prefix operator. Во второй строке op обозначает унарное Постфиксное ++ и -- операторы.In the second entry, op denotes the unary postfix ++ and -- operators. В третьей записи op обозначает любой требуется перегружаемый бинарный оператор.In the third entry, op denotes any overloadable binary operator.

Нотация оператораOperator notation Функциональная нотацияFunctional notation
op x operator op(x)
x op operator op(x)
x op y operator op(x,y)

Определяемый пользователем оператор объявления всегда требуется хотя бы один параметр типа класса или структуры, содержащий объявления оператора.User-defined operator declarations always require at least one of the parameters to be of the class or struct type that contains the operator declaration. Таким образом он не поддерживается для определяемого пользователем оператора иметь ту же сигнатуру, что встроенному оператору.Thus, it is not possible for a user-defined operator to have the same signature as a predefined operator.

Определяемый пользователем оператор объявления не может изменить синтаксис, приоритет и ассоциативность оператора.User-defined operator declarations cannot modify the syntax, precedence, or associativity of an operator. Например / оператор всегда является бинарным оператором, всегда имеет уровень приоритета, указанное в приоритет и ассоциативность операторови всегда левую ассоциативность.For example, the / operator is always a binary operator, always has the precedence level specified in Operator precedence and associativity, and is always left-associative.

Хотя для определяемого пользователем оператора для выполнения любых вычислений, что, реализаций, которые формируют результаты, отличные от тех, которые ожидаются интуитивно понятным образом не рекомендуется.While it is possible for a user-defined operator to perform any computation it pleases, implementations that produce results other than those that are intuitively expected are strongly discouraged. Например, реализация operator == следует сравнить два операнда на предмет равенства и возвращает соответствующий bool результат.For example, an implementation of operator == should compare the two operands for equality and return an appropriate bool result.

Описания отдельных операторов в основные выражения через условные логические операторы указать операторы и любые дополнительные правила, которые применяются стандартные реализации для каждого оператора.The descriptions of individual operators in Primary expressions through Conditional logical operators specify the predefined implementations of the operators and any additional rules that apply to each operator. Описания использовать условий разрешение перегрузки унарного оператора, разрешить перегрузку бинарного оператора, и Числовое расширение, определения элементов найти в следующих разделах.The descriptions make use of the terms unary operator overload resolution, binary operator overload resolution, and numeric promotion, definitions of which are found in the following sections.

Разрешение перегрузки унарного оператораUnary operator overload resolution

Операции формы op x или x op, где op перегружаемый унарный оператор, и x является выражением типа X, обрабатывается следующим образом:An operation of the form op x or x op, where op is an overloadable unary operator, and x is an expression of type X, is processed as follows:

  • Набор кандидатов определяемые пользователем операторы, предоставляемые X для операции operator op(x) определяется с использованием правил кандидата определяемых пользователем операторов.The set of candidate user-defined operators provided by X for the operation operator op(x) is determined using the rules of Candidate user-defined operators.
  • Если набор кандидатов определяемые пользователем операторы не пустой, это становится набор операторов-кандидатов для операции.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. В противном случае заранее определенной унарной operator op становятся реализации, поднятые формы, включая набор операторов-кандидатов для операции.Otherwise, the predefined unary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. Стандартные реализации данного оператора указаны в описании оператора (основные выражения и унарные операторы).The predefined implementations of a given operator are specified in the description of the operator (Primary expressions and Unary operators).
  • Правила разрешения перегрузки из разрешение перегрузки применяются к набору операторов кандидатов, чтобы выбрать подходящий оператор списка аргументов (x), и этот оператор становится результатом перегрузки процесс разрешения.The overload resolution rules of Overload resolution are applied to the set of candidate operators to select the best operator with respect to the argument list (x), and this operator becomes the result of the overload resolution process. Если разрешение перегрузки оканчивается неудачей выбрать один подходящий оператор, возникает ошибка времени привязки.If overload resolution fails to select a single best operator, a binding-time error occurs.

Разрешение перегрузки бинарного оператораBinary operator overload resolution

Операции формы x op y, где op является требуется перегружаемый бинарный оператор x является выражением типа X, и y является выражением типа Y, обрабатывается следующим образом:An operation of the form x op y, where op is an overloadable binary operator, x is an expression of type X, and y is an expression of type Y, is processed as follows:

  • Набор кандидатов определяемые пользователем операторы, предоставляемые X и Y для операции operator op(x,y) определяется.The set of candidate user-defined operators provided by X and Y for the operation operator op(x,y) is determined. Набор состоит из объединения операторов-кандидатов, предоставляемые X и потенциальных операторы, предоставляемые Y, каждый определенный, используя правила кандидата определяемых пользователем операторов.The set consists of the union of the candidate operators provided by X and the candidate operators provided by Y, each determined using the rules of Candidate user-defined operators. Если X и Y относятся к одному типу, или если X и Y являются производными от общего базового типа, а затем Общие операторы-кандидаты произведен только в объединенном наборе один раз.If X and Y are the same type, or if X and Y are derived from a common base type, then shared candidate operators only occur in the combined set once.
  • Если набор кандидатов определяемые пользователем операторы не пустой, это становится набор операторов-кандидатов для операции.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. В противном случае двоичные стандартные operator op становятся реализации, поднятые формы, включая набор операторов-кандидатов для операции.Otherwise, the predefined binary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. Стандартные реализации данного оператора указаны в описании оператора (арифметические операторы через условные логические операторы).The predefined implementations of a given operator are specified in the description of the operator (Arithmetic operators through Conditional logical operators). Для стандартных операторов перечислений и делегатов Единственными операторами считается определяются перечисление или делегат типа, который является типом времени привязки одного из операндов.For predefined enum and delegate operators, the only operators considered are those defined by an enum or delegate type that is the binding-time type of one of the operands.
  • Правила разрешения перегрузки из разрешение перегрузки применяются к набору операторов кандидатов, чтобы выбрать подходящий оператор списка аргументов (x,y), и этот оператор становится результатом перегрузки процесс разрешения.The overload resolution rules of Overload resolution are applied to the set of candidate operators to select the best operator with respect to the argument list (x,y), and this operator becomes the result of the overload resolution process. Если разрешение перегрузки оканчивается неудачей выбрать один подходящий оператор, возникает ошибка времени привязки.If overload resolution fails to select a single best operator, a binding-time error occurs.

Определяемые пользователем операторы кандидатовCandidate user-defined operators

Типом T , операция operator op(A), где op перегружаемый оператор и A является список аргументов, набор кандидатов, определяемые пользователем операторы, предоставляемые T для operator op(A) определяется как показано ниже:Given a type T and an operation operator op(A), where op is an overloadable operator and A is an argument list, the set of candidate user-defined operators provided by T for operator op(A) is determined as follows:

  • Определить тип T0.Determine the type T0. Если T является тип nullable T0 является его базовым типом, в противном случае T0 равен T.If T is a nullable type, T0 is its underlying type, otherwise T0 is equal to T.
  • Для всех operator op объявления в T0 и все удален виды таких операторов, если хотя бы один оператор (применимого члена функции) списка аргументов A, то набор операторы кандидатов состоит из таких применимых операторов в T0.For all operator op declarations in T0 and all lifted forms of such operators, if at least one operator is applicable (Applicable function member) with respect to the argument list A, then the set of candidate operators consists of all such applicable operators in T0.
  • В противном случае, если T0 является object, набор операторов-кандидатов пуст.Otherwise, if T0 is object, the set of candidate operators is empty.
  • В противном случае набор операторов кандидатов, предоставляемые T0 — это набор операторов-кандидатов, предоставляемые прямой базовый класс для T0, или эффективный базовый класс T0 Если T0 является параметром типа.Otherwise, the set of candidate operators provided by T0 is the set of candidate operators provided by the direct base class of T0, or the effective base class of T0 if T0 is a type parameter.

Восходящие приведения числовых типовNumeric promotions

Числовое расширение состоит из автоматически выполняет определенные неявные преобразования предопределенные унарные и бинарные операторы числовых операндов.Numeric promotion consists of automatically performing certain implicit conversions of the operands of the predefined unary and binary numeric operators. Числовое расширение — это не отдельный механизм, а скорее эффект применения разрешения перегрузки для стандартных операторов.Numeric promotion is not a distinct mechanism, but rather an effect of applying overload resolution to the predefined operators. Числовое расширение специально не влияет на вычисления определяемых пользователем операторов, несмотря на то, что определяемые пользователем операторы можно реализовать для получения похожих эффектов.Numeric promotion specifically does not affect evaluation of user-defined operators, although user-defined operators can be implemented to exhibit similar effects.

В качестве примера числовых повышения роли, рассмотрим стандартные реализации двоичного файла * оператор:As an example of numeric promotion, consider the predefined implementations of the binary * operator:

int operator *(int x, int y);
uint operator *(uint x, uint y);
long operator *(long x, long y);
ulong operator *(ulong x, ulong y);
float operator *(float x, float y);
double operator *(double x, double y);
decimal operator *(decimal x, decimal y);

Когда правила разрешения перегрузки (разрешение перегрузки) применяются к этому набору операторов, применяется для выбора первого из операторов, для которых существуют неявные преобразования из типы операндов.When overload resolution rules (Overload resolution) are applied to this set of operators, the effect is to select the first of the operators for which implicit conversions exist from the operand types. Например, для операции b * s, где bbyte и sshort, разрешения перегрузки выбирается operator *(int,int) как оператор рекомендации.For example, for the operation b * s, where b is a byte and s is a short, overload resolution selects operator *(int,int) as the best operator. Таким образом, это действие соответствует b и s преобразуются в int, а тип результата — int.Thus, the effect is that b and s are converted to int, and the type of the result is int. Аналогичным образом, для операции i * d, где iint и ddouble, разрешения перегрузки выбирается operator *(double,double) как оператор рекомендации.Likewise, for the operation i * d, where i is an int and d is a double, overload resolution selects operator *(double,double) as the best operator.

Числовое расширение унарных операторовUnary numeric promotions

Унарный Числовое расширение выполняется для операндов предопределенного +, -, и ~ унарные операторы.Unary numeric promotion occurs for the operands of the predefined +, -, and ~ unary operators. Числовое расширение унарный состоит всего лишь преобразования операндов типа sbyte, byte, short, ushort, или char ввода int.Unary numeric promotion simply consists of converting operands of type sbyte, byte, short, ushort, or char to type int. Кроме того, для унарных - оператор, унарный Числовое расширение преобразует операнды типа uint ввода long.Additionally, for the unary - operator, unary numeric promotion converts operands of type uint to type long.

Числовое расширение бинарных операторовBinary numeric promotions

Числовое расширение выполняется для операндов предопределенного +, -, *, /, %, &, |, ^, ==, !=, >, <, >=, и <= бинарных операторов.Binary numeric promotion occurs for the operands of the predefined +, -, *, /, %, &, |, ^, ==, !=, >, <, >=, and <= binary operators. Числовое расширение оба операнда преобразуются в общий тип, который в случае операторов, также становится тип результата операции.Binary numeric promotion implicitly converts both operands to a common type which, in case of the non-relational operators, also becomes the result type of the operation. Числовое расширение состоит в применении следующие правила, в порядке, в котором они отображаются здесь:Binary numeric promotion consists of applying the following rules, in the order they appear here:

  • Если один из операндов имеет тип decimal, то другой операнд преобразуется в тип decimal, или возникает ошибка времени привязки, если другой операнд имеет тип float или double.If either operand is of type decimal, the other operand is converted to type decimal, or a binding-time error occurs if the other operand is of type float or double.
  • В противном случае, если один из операндов имеет тип double, то другой операнд преобразуется в тип double.Otherwise, if either operand is of type double, the other operand is converted to type double.
  • В противном случае, если один из операндов имеет тип float, то другой операнд преобразуется в тип float.Otherwise, if either operand is of type float, the other operand is converted to type float.
  • В противном случае, если один из операндов имеет тип ulong, то другой операнд преобразуется в тип ulong, или возникает ошибка времени привязки, если другой операнд имеет тип sbyte, short, int, или long.Otherwise, if either operand is of type ulong, the other operand is converted to type ulong, or a binding-time error occurs if the other operand is of type sbyte, short, int, or long.
  • В противном случае, если один из операндов имеет тип long, то другой операнд преобразуется в тип long.Otherwise, if either operand is of type long, the other operand is converted to type long.
  • В противном случае, если один из операндов имеет тип uint и другой операнд имеет тип sbyte, short, или int, оба операнда преобразуются в тип long.Otherwise, if either operand is of type uint and the other operand is of type sbyte, short, or int, both operands are converted to type long.
  • В противном случае, если один из операндов имеет тип uint, то другой операнд преобразуется в тип uint.Otherwise, if either operand is of type uint, the other operand is converted to type uint.
  • В противном случае оба операнда преобразуются в тип int.Otherwise, both operands are converted to type int.

Обратите внимание, что первое правило запрещает любые операции, сочетающие в себе decimal тип с double и float типов.Note that the first rule disallows any operations that mix the decimal type with the double and float types. Это правило вытекает из тот факт, что отсутствуют неявные преобразования между decimal типа и double и float типов.The rule follows from the fact that there are no implicit conversions between the decimal type and the double and float types.

Также Обратите внимание, что операнд типа ulong Если другой операнд относится целочисленным типом со знаком.Also note that it is not possible for an operand to be of type ulong when the other operand is of a signed integral type. Причина в том, что целочисленный тип не существует, может представлять весь спектр ulong и целочисленных типов со знаком.The reason is that no integral type exists that can represent the full range of ulong as well as the signed integral types.

В обоих указанных случаях можно использовать для явного преобразования один операнд с типом, который совместим с другой операнд выражения приведения.In both of the above cases, a cast expression can be used to explicitly convert one operand to a type that is compatible with the other operand.

В примереIn the example

decimal AddPercent(decimal x, double percent) {
    return x * (1.0 + percent / 100.0);
}

во время привязки возникает из-за decimal нельзя будет умножено на double.a binding-time error occurs because a decimal cannot be multiplied by a double. Эта ошибка устраняется путем явного преобразования второго операнда decimal, как показано ниже:The error is resolved by explicitly converting the second operand to decimal, as follows:

decimal AddPercent(decimal x, double percent) {
    return x * (decimal)(1.0 + percent / 100.0);
}

Поднятые операторыLifted operators

Снято операторы разрешить стандартные и определяемые пользователем операторы, которые работают с типами не поддерживающий значение NULL, также можно использовать с обнуляемых типов.Lifted operators permit predefined and user-defined operators that operate on non-nullable value types to also be used with nullable forms of those types. Поднятые операторы формируются на основе предопределенных и определяемых пользователем операторов, которые соответствуют определенным требованиям, как описано в следующем примере:Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:

  • Для унарных операторовFor the unary operators

    +  ++  -  --  !  ~
    

    поднятые форма оператора существует, если типы операнд и результат обоих типов не поддерживающий значение NULL.a lifted form of an operator exists if the operand and result types are both non-nullable value types. Поднятые формы строится путем добавления одного ? модификатор типы операнд и результат.The lifted form is constructed by adding a single ? modifier to the operand and result types. Поднятые оператор создает значение null, если операнд имеет значение null.The lifted operator produces a null value if the operand is null. В противном случае оператор ликвидированный распаковывает операнд, применяется базовый оператор и заключает результат.Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.

  • Для бинарных операторовFor the binary operators

    +  -  *  /  %  &  |  ^  <<  >>
    

    поднятые форма оператора существует, если операнд и результат типы являются все типы значений, не допускающие значения NULL.a lifted form of an operator exists if the operand and result types are all non-nullable value types. Поднятые формы строится путем добавления одного ? модификатор к каждому типу операнд и результат.The lifted form is constructed by adding a single ? modifier to each operand and result type. Поднятые оператор создает значение null, если один или оба операнда имеют значение null (исключением & и | операторы bool? типов, как описано в логические операторы).The lifted operator produces a null value if one or both operands are null (an exception being the & and | operators of the bool? type, as described in Boolean logical operators). В противном случае оператор ликвидированный распаковывает операндов, применяется базовый оператор и заключает результат.Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.

  • Для операторов равенстваFor the equality operators

    ==  !=
    

    поднятые форма оператора существует, если доступны типы операндов не поддерживающий значение NULL типов и если тип результата — bool.a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool. Поднятые формы строится путем добавления одного ? модификатор для каждого типа операнда.The lifted form is constructed by adding a single ? modifier to each operand type. Оператор ликвидированный считает, что два значения null равны и значение null не равны, если любое значение, отличное от null.The lifted operator considers two null values equal, and a null value unequal to any non-null value. Если оба операнда не равны null, оператор ликвидированный распаковывает операнды и применяется базовый оператор для создания bool результат.If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

  • Для операторов отношенияFor the relational operators

    <  >  <=  >=
    

    поднятые форма оператора существует, если доступны типы операндов не поддерживающий значение NULL типов и если тип результата — bool.a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool. Поднятые формы строится путем добавления одного ? модификатор для каждого типа операнда.The lifted form is constructed by adding a single ? modifier to each operand type. Оператор ликвидированный создающее значение false Если один или оба операнда имеют значение null.The lifted operator produces the value false if one or both operands are null. В противном случае оператор ликвидированный распаковывает операнды и применяется базовый оператор для создания bool результат.Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

Поиск членаMember lookup

Поиск члена — это процесс, посредством которого определяется значение имени в контексте типа.A member lookup is the process whereby the meaning of a name in the context of a type is determined. Поиск членов может выполняться как часть оценки simple_name (простые имена) или member_access (доступ к членам) в выражение.A member lookup can occur as part of evaluating a simple_name (Simple names) or a member_access (Member access) in an expression. Если simple_name или member_access возникает как primary_expression из invocation_expression ( Вызовы методов), говорят, что член должен быть вызван.If the simple_name or member_access occurs as the primary_expression of an invocation_expression (Method invocations), the member is said to be invoked.

Если элемент является метод или событие, или в том случае, если это константа, поле или свойство типа делегата (делегаты) или тип dynamic (динамический тип), то считается, что член является invocable.If a member is a method or event, or if it is a constant, field or property of either a delegate type (Delegates) or the type dynamic (The dynamic type), then the member is said to be invocable.

Поиск члена считает, что не только имя члена, но число параметров типа, элемента и доступен ли элемент.Member lookup considers not only the name of a member but also the number of type parameters the member has and whether the member is accessible. В целях поиска членов универсальные методы и вложенные универсальные типы имеют число параметров типа, указанного в соответствующих объявлениях, и у всех остальных членов параметров типа.For the purposes of member lookup, generic methods and nested generic types have the number of type parameters indicated in their respective declarations and all other members have zero type parameters.

Поиск члена с именем N с K  параметры типа в типе T обрабатывается следующим образом:A member lookup of a name N with K type parameters in a type T is processed as follows:

  • Во-первых, набор доступных членов с именем N определяется:First, a set of accessible members named N is determined:
    • Если T является параметром типа, а затем набор представляет собой объединение наборов доступных членов с именем N в каждом из типов, заданный как ограничение первичного или вторичного ограничения (ограничения параметров типа) для  T, а также набор доступных членов с именем N в object.If T is a type parameter, then the set is the union of the sets of accessible members named N in each of the types specified as a primary constraint or secondary constraint (Type parameter constraints) for T, along with the set of accessible members named N in object.
    • В противном случае набор включает все эти возможности доступны (доступ к членам) члены с именем N в T, включая унаследованные члены и доступные члены с именем N в object.Otherwise, the set consists of all accessible (Member access) members named N in T, including inherited members and the accessible members named N in object. Если T — сконструированный тип, набор элементов получается путем замены аргументов типа, как описано в разделе члены сконструированных типов.If T is a constructed type, the set of members is obtained by substituting type arguments as described in Members of constructed types. Члены, включающие override модификатор исключаются из набора.Members that include an override modifier are excluded from the set.
  • Далее, если K равно нулю, все вложенные типы, чьи объявления содержат параметры типа удаляются.Next, if K is zero, all nested types whose declarations include type parameters are removed. Если K не равно 0, все члены с различным числом удалены параметры типа.If K is not zero, all members with a different number of type parameters are removed. Обратите внимание, что при K равно нулю, методы не тип параметров, не удаляются, так как процесс определения типа (вывод типа) можно попытаться определить аргументы типа.Note that when K is zero, methods having type parameters are not removed, since the type inference process (Type inference) might be able to infer the type arguments.
  • Затем, если член является вызывается, все-invocable элементы удаляются из набора.Next, if the member is invoked, all non-invocable members are removed from the set.
  • Затем члены, которые скрыты другими членами удаляются из набора.Next, members that are hidden by other members are removed from the set. Для каждого члена S.M в наборе, где S — это тип, в которой элемент M был объявлен, применяются следующие правила:For every member S.M in the set, where S is the type in which the member M is declared, the following rules are applied:
    • Если M является константой, поля, свойства, события или член перечисления, то все члены, объявленные в базовом типе S удаляются из набора.If M is a constant, field, property, event, or enumeration member, then all members declared in a base type of S are removed from the set.
    • Если M объявление типа, то все не типы, объявленные в базовом типе S удаляются из набора, и все объявления, с числом параметров типа в качестве типов M объявленный в базовом типе S удаляются из набора.If M is a type declaration, then all non-types declared in a base type of S are removed from the set, and all type declarations with the same number of type parameters as M declared in a base type of S are removed from the set.
    • Если M является методом, а затем все не являющийся методом члены, объявленные в базовом типе S удаляются из набора.If M is a method, then all non-method members declared in a base type of S are removed from the set.
  • После этого члены интерфейса, скрытые члены класса, удаляются из набора.Next, interface members that are hidden by class members are removed from the set. Этот шаг действует только если T является параметром типа и T имеет оба действительного базового класса, отличное от object и эффективный интерфейс непустое значение (ограничения параметров типа).This step only has an effect if T is a type parameter and T has both an effective base class other than object and a non-empty effective interface set (Type parameter constraints). Для каждого члена S.M в наборе, где S — это тип, в которой элемент M был объявлен, следующие правила применяются в том случае, если S является объявлением класса, отличного от object:For every member S.M in the set, where S is the type in which the member M is declared, the following rules are applied if S is a class declaration other than object:
    • Если M является константой, поля, свойства, события, члена перечисления или объявление типа, то все члены, объявленные в объявлении интерфейса удаляются из набора.If M is a constant, field, property, event, enumeration member, or type declaration, then all members declared in an interface declaration are removed from the set.
    • Если M является методом, а затем из набора, а также все методы, имеющие ту же сигнатуру, что удаляются все не являющийся методом члены, объявленные в объявлении интерфейса M объявлен в интерфейсе объявления удаляются из набора.If M is a method, then all non-method members declared in an interface declaration are removed from the set, and all methods with the same signature as M declared in an interface declaration are removed from the set.
  • Наконец после удаления скрытых членов, определяется результат уточняющего запроса.Finally, having removed hidden members, the result of the lookup is determined:
    • Если набор состоит из одного члена, который не является методом, этот член является результатом поиска.If the set consists of a single member that is not a method, then this member is the result of the lookup.
    • В противном случае если набор содержит только методы, эта группа методов является результатом поиска.Otherwise, if the set contains only methods, then this group of methods is the result of the lookup.
    • В противном случае уточняющего запроса является неоднозначным, и возникает ошибка во время привязки.Otherwise, the lookup is ambiguous, and a binding-time error occurs.

Для поиска элемента в типы, отличные от параметров типов и интерфейсов и член уточняющих запросов в интерфейсы, которые являются строго одиночным наследованием (каждый интерфейс в цепочке наследования имеет точно ноль или один прямой базовый интерфейс), в результате правила просто, производным скрыть члены базовых членов с тем же именем или сигнатурой.For member lookups in types other than type parameters and interfaces, and member lookups in interfaces that are strictly single-inheritance (each interface in the inheritance chain has exactly zero or one direct base interface), the effect of the lookup rules is simply that derived members hide base members with the same name or signature. Такой поиск одиночного наследования никогда не являются неоднозначными.Such single-inheritance lookups are never ambiguous. Неоднозначности, которые могут возникать из члена уточняющих запросов в интерфейсы множественного наследования, описаны в доступ к членам интерфейса.The ambiguities that can possibly arise from member lookups in multiple-inheritance interfaces are described in Interface member access.

Базовые типыBase types

Для поиска членов, тип T видимости, имеет следующие базовые типы:For purposes of member lookup, a type T is considered to have the following base types:

  • Если Tobject, затем T не имеет базового типа.If T is object, then T has no base type.
  • Если Tenum_type, базовые типы T относятся к типам классов System.Enum, System.ValueType, и object.If T is an enum_type, the base types of T are the class types System.Enum, System.ValueType, and object.
  • Если Tstruct_type, базовые типы T относятся к типам классов System.ValueType и object.If T is a struct_type, the base types of T are the class types System.ValueType and object.
  • Если Tclass_type, базовые типы T являются базовыми классами из T, включая тип класса object.If T is a class_type, the base types of T are the base classes of T, including the class type object.
  • Если Tinterface_type, базовые типы T являются базовые интерфейсы T и тип класса object.If T is an interface_type, the base types of T are the base interfaces of T and the class type object.
  • Если Tarray_type, базовые типы T относятся к типам классов System.Array и object.If T is an array_type, the base types of T are the class types System.Array and object.
  • Если Tdelegate_type, базовые типы T относятся к типам классов System.Delegate и object.If T is a delegate_type, the base types of T are the class types System.Delegate and object.

Функции-членыFunction members

Функции-члены — члены, содержащие исполняемые операторы.Function members are members that contain executable statements. Функции-члены всегда являются членами типов и не может быть членами пространства имен.Function members are always members of types and cannot be members of namespaces. C# определяет следующие категории функций-членов:C# defines the following categories of function members:

  • МетодыMethods
  • СвойстваProperties
  • СобытияEvents
  • ИндексаторыIndexers
  • Определяемые пользователем операторыUser-defined operators
  • Конструкторы экземпляровInstance constructors
  • Статические конструкторыStatic constructors
  • ДеструкторыDestructors

За исключением деструкторы и статические конструкторы (которые могут быть вызваны явно) инструкций, содержащихся в функции-члены, выполняются через вызовов функций-членов.Except for destructors and static constructors (which cannot be invoked explicitly), the statements contained in function members are executed through function member invocations. Фактический синтаксис вызова функции-члена зависит от категории конкретной функции-члена.The actual syntax for writing a function member invocation depends on the particular function member category.

Список аргументов (списки аргументов) функции-члена вызова предоставляет фактические значения или ссылки на переменные для параметров функции-члена.The argument list (Argument lists) of a function member invocation provides actual values or variable references for the parameters of the function member.

Вызовы универсальных методов, могут использовать определение типа для определения набора аргументов типа для передачи в метод.Invocations of generic methods may employ type inference to determine the set of type arguments to pass to the method. Этот процесс описан в вывод типа.This process is described in Type inference.

Вызовы методов, индексаторов, операторов и конструкторов экземпляров использовать разрешение перегрузки, чтобы определить, какой набор кандидатов для вызова функций-членов.Invocations of methods, indexers, operators and instance constructors employ overload resolution to determine which of a candidate set of function members to invoke. Этот процесс описан в разрешение перегрузки.This process is described in Overload resolution.

После определения конкретной функции-члена во время привязки, возможно через разрешения перегрузки, фактический процесс выполнения вызова функции-члена описан в Проверка динамического разрешения перегрузкивовремякомпиляции.Once a particular function member has been identified at binding-time, possibly through overload resolution, the actual run-time process of invoking the function member is described in Compile-time checking of dynamic overload resolution.

В следующей таблице перечислены обработку, которая выполняется в конструкции, включающих шесть категорий функций-членов, которые можно вызвать явным образом.The following table summarizes the processing that takes place in constructs involving the six categories of function members that can be explicitly invoked. В таблице e, x, y, и value указания выражений, которые классифицируются как переменные или значения, T означает выражение как тип, F — простое имя метода и P — это простое имя свойства.In the table, e, x, y, and value indicate expressions classified as variables or values, T indicates an expression classified as a type, F is the simple name of a method, and P is the simple name of a property.

КонструкцияConstruct ПримерExample ОписаниеDescription
Вызов методаMethod invocation F(x,y) Разрешение перегрузки применяется для выбора подходящего метода F в содержащем классе или структуре.Overload resolution is applied to select the best method F in the containing class or struct. Метод вызывается со списком аргументов (x,y).The method is invoked with the argument list (x,y). Если метод не является static, выражение экземпляра имеет this.If the method is not static, the instance expression is this.
T.F(x,y) Разрешение перегрузки применяется для выбора подходящего метода F в классе или структуре T.Overload resolution is applied to select the best method F in the class or struct T. Ошибка времени привязки возникает, если метод не является static.A binding-time error occurs if the method is not static. Метод вызывается со списком аргументов (x,y).The method is invoked with the argument list (x,y).
e.F(x,y) Разрешение перегрузки применяется для выбора наиболее подходящего метода F в класса, структуры или интерфейса, передаваемом типе e.Overload resolution is applied to select the best method F in the class, struct, or interface given by the type of e. Возникает ошибка времени привязки, если метод static.A binding-time error occurs if the method is static. Метод вызывается с выражением экземпляра e и список аргументов (x,y).The method is invoked with the instance expression e and the argument list (x,y).
Доступ к свойствуProperty access P get Метод доступа свойства P вызывается в содержащем классе или структуре.The get accessor of the property P in the containing class or struct is invoked. Ошибка времени компиляции возникает, если P доступен только для записи.A compile-time error occurs if P is write-only. Если P не static, выражение экземпляра имеет this.If P is not static, the instance expression is this.
P = value set Метод доступа свойства P в содержащем классе или структуре вызывается со списком аргументов (value).The set accessor of the property P in the containing class or struct is invoked with the argument list (value). Ошибка времени компиляции возникает, если P доступен только для чтения.A compile-time error occurs if P is read-only. Если P не static, выражение экземпляра имеет this.If P is not static, the instance expression is this.
T.P get Метод доступа свойства P в классе или структуре T вызывается.The get accessor of the property P in the class or struct T is invoked. Ошибка времени компиляции возникает, если P не static или, если P доступен только для записи.A compile-time error occurs if P is not static or if P is write-only.
T.P = value set Метод доступа свойства P в классе или структуре T вызывается со списком аргументов (value).The set accessor of the property P in the class or struct T is invoked with the argument list (value). Ошибка времени компиляции возникает, если P не static или, если P доступен только для чтения.A compile-time error occurs if P is not static or if P is read-only.
e.P get Метод доступа свойства P в класса, структуры или интерфейса, передаваемом типе e вызывается с выражением экземпляра e.The get accessor of the property P in the class, struct, or interface given by the type of e is invoked with the instance expression e. Ошибка во время привязки возникает, если Pstatic или, если P доступен только для записи.A binding-time error occurs if P is static or if P is write-only.
e.P = value set Метод доступа свойства P в класса, структуры или интерфейса, передаваемом типе e вызывается с выражением экземпляра e и список аргументов (value).The set accessor of the property P in the class, struct, or interface given by the type of e is invoked with the instance expression e and the argument list (value). Ошибка во время привязки возникает, если Pstatic или, если P доступен только для чтения.A binding-time error occurs if P is static or if P is read-only.
Доступ к событиямEvent access E += value add Метод доступа события E вызывается в содержащем классе или структуре.The add accessor of the event E in the containing class or struct is invoked. Если E является не статическим, выражение экземпляра имеет this.If E is not static, the instance expression is this.
E -= value remove Метод доступа события E вызывается в содержащем классе или структуре.The remove accessor of the event E in the containing class or struct is invoked. Если E является не статическим, выражение экземпляра имеет this.If E is not static, the instance expression is this.
T.E += value add Метод доступа события E в классе или структуре T вызывается.The add accessor of the event E in the class or struct T is invoked. Ошибка во время привязки возникает, если E не является статическим.A binding-time error occurs if E is not static.
T.E -= value remove Метод доступа события E в классе или структуре T вызывается.The remove accessor of the event E in the class or struct T is invoked. Ошибка во время привязки возникает, если E не является статическим.A binding-time error occurs if E is not static.
e.E += value add Метод доступа события E в класса, структуры или интерфейса, передаваемом типе e вызывается с выражением экземпляра e.The add accessor of the event E in the class, struct, or interface given by the type of e is invoked with the instance expression e. Ошибка во время привязки возникает, если E является статическим.A binding-time error occurs if E is static.
e.E -= value remove Метод доступа события E в класса, структуры или интерфейса, передаваемом типе e вызывается с выражением экземпляра e.The remove accessor of the event E in the class, struct, or interface given by the type of e is invoked with the instance expression e. Ошибка во время привязки возникает, если E является статическим.A binding-time error occurs if E is static.
Доступ к индексаторуIndexer access e[x,y] Разрешение перегрузки применяется для выбора наиболее подходящего индексатора в класса, структуры или интерфейса, передаваемом типе e.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. get С выражением экземпляра вызывается метод доступа индексатора e и список аргументов (x,y).The get accessor of the indexer is invoked with the instance expression e and the argument list (x,y). Ошибка времени привязки возникает, если индексатор доступен только для записи.A binding-time error occurs if the indexer is write-only.
e[x,y] = value Разрешение перегрузки применяется для выбора наиболее подходящего индексатора в класса, структуры или интерфейса, передаваемом типе e.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. set С выражением экземпляра вызывается метод доступа индексатора e и список аргументов (x,y,value).The set accessor of the indexer is invoked with the instance expression e and the argument list (x,y,value). Ошибка времени привязки возникает, если индексатор доступен только для чтения.A binding-time error occurs if the indexer is read-only.
Вызов оператораOperator invocation -x Разрешение перегрузки применяется для выбора наиболее подходящего унарного оператора в классе или структуре, передаваемой по типу x.Overload resolution is applied to select the best unary operator in the class or struct given by the type of x. Выбранный оператор вызывается со списком аргументов (x).The selected operator is invoked with the argument list (x).
x + y Разрешение перегрузки применяется для выбора наиболее подходящего бинарного оператора в классах или структурах, передаваемых типы x и y.Overload resolution is applied to select the best binary operator in the classes or structs given by the types of x and y. Выбранный оператор вызывается со списком аргументов (x,y).The selected operator is invoked with the argument list (x,y).
Вызов конструктора экземпляраInstance constructor invocation new T(x,y) Разрешение перегрузки применяется для выбора наиболее конструктор экземпляра в классе или структуре T.Overload resolution is applied to select the best instance constructor in the class or struct T. Конструктор экземпляра вызывается со списком аргументов (x,y).The instance constructor is invoked with the argument list (x,y).

Списки аргументовArgument lists

Каждый вызов функции члена и делегат содержит список аргументов, который предоставляет фактические значения или ссылки на переменные для параметров функции-члена.Every function member and delegate invocation includes an argument list which provides actual values or variable references for the parameters of the function member. Синтаксис для указания списка аргументов вызова функции-члена зависит от категории функции-члена:The syntax for specifying the argument list of a function member invocation depends on the function member category:

  • Для экземпляра конструкторов, методов, индексаторов и делегатов, аргументы указываются как argument_list, как описано ниже.For instance constructors, methods, indexers and delegates, the arguments are specified as an argument_list, as described below. Для индексаторов, при вызове set метода доступа, список аргументов дополнительно включает выражение, указанное в качестве правого операнда оператора присваивания.For indexers, when invoking the set accessor, the argument list additionally includes the expression specified as the right operand of the assignment operator.
  • Для свойств, список аргументов пуст, при вызове get метод доступа и состоит из выражения, указанного в качестве правого операнда оператора присваивания, при вызове set метода доступа.For properties, the argument list is empty when invoking the get accessor, and consists of the expression specified as the right operand of the assignment operator when invoking the set accessor.
  • Для событий, список аргументов, состоит из выражения, указанного в качестве правого операнда оператора += или -= оператор.For events, the argument list consists of the expression specified as the right operand of the += or -= operator.
  • Для определяемых пользователем операторов список аргументов состоит из одного операнда унарный оператор или два операнда бинарного оператора.For user-defined operators, the argument list consists of the single operand of the unary operator or the two operands of the binary operator.

Аргументы свойств (свойства), события (события) и определяемые пользователем операторы (операторы), всегда передаются в качестве значения параметров ( Параметры по значению).The arguments of properties (Properties), events (Events), and user-defined operators (Operators) are always passed as value parameters (Value parameters). Аргументы индексаторов (индексаторы), всегда передаются в качестве значения параметров (параметры по значению) или массивы параметров (массивы параметров).The arguments of indexers (Indexers) are always passed as value parameters (Value parameters) or parameter arrays (Parameter arrays). Ссылки и выходные параметры не поддерживаются для следующих категорий функций-членов.Reference and output parameters are not supported for these categories of function members.

Аргументы вызова конструктора, метода, индексатора или делегата экземпляр указываются как argument_list:The arguments of an instance constructor, method, indexer or delegate invocation are specified as an argument_list:

argument_list
    : argument (',' argument)*
    ;

argument
    : argument_name? argument_value
    ;

argument_name
    : identifier ':'
    ;

argument_value
    : expression
    | 'ref' variable_reference
    | 'out' variable_reference
    ;

Argument_list состоит из одного или нескольких аргументs, разделенных запятыми.An argument_list consists of one or more arguments, separated by commas. Каждый аргумент состоит из необязательного имя_аргумента следуют argument_value.Each argument consists of an optional argument_name followed by an argument_value. Аргумент с имя_аргумента называется именованный аргумент, тогда как аргумент без имя_аргументапозиционный аргумент.An argument with an argument_name is referred to as a named argument, whereas an argument without an argument_name is a positional argument. Это ошибка для позиционного аргумента отображения после именованный аргумент в argument_list.It is an error for a positional argument to appear after a named argument in an argument_list.

Argument_value может принимать одно из следующих форм:The argument_value can take one of the following forms:

Соответствующие параметрыCorresponding parameters

Для каждого аргумента в списке аргументов должен быть соответствующего параметра в функции-члена или вызываемого делегата.For each argument in an argument list there has to be a corresponding parameter in the function member or delegate being invoked.

Список параметров, используемые в следующем примере определяется следующим образом:The parameter list used in the following is determined as follows:

  • Виртуальные методы и индексаторы, определенные в классах список параметров выбирается из наиболее подходящего объявления или переопределить функции-члена, начиная с статический тип получателя и поиск в его базовых классов.For virtual methods and indexers defined in classes, the parameter list is picked from the most specific declaration or override of the function member, starting with the static type of the receiver, and searching through its base classes.
  • Методы интерфейса и индексаторы, выбирается в списке параметров формирования определение наиболее конкретный элемент, начиная с типом интерфейса и поиск в базовых интерфейсов.For interface methods and indexers, the parameter list is picked form the most specific definition of the member, starting with the interface type and searching through the base interfaces. Если список уникальных параметров найден, создается список параметров с недоступными именами и без необязательных параметров, таким образом, чтобы вызовы нельзя использовать именованные параметры или пропустить необязательные аргументы.If no unique parameter list is found, a parameter list with inaccessible names and no optional parameters is constructed, so that invocations cannot use named parameters or omit optional arguments.
  • Для разделяемых методов используется список параметров определяющее объявление разделяемого метода.For partial methods, the parameter list of the defining partial method declaration is used.
  • Для всех других функций-членов и делегаты имеется только один список параметров, который будет использоваться.For all other function members and delegates there is only a single parameter list, which is the one used.

Позиция аргумента или параметра определяется как число аргументов или параметров, предшествует ей в списке аргументов или списка параметров.The position of an argument or parameter is defined as the number of arguments or parameters preceding it in the argument list or parameter list.

Соответствующие параметры для аргументов членов функции устанавливаются следующим образом:The corresponding parameters for function member arguments are established as follows:

  • Аргументы в argument_list конструкторы экземпляров, методов, индексаторов и делегатов:Arguments in the argument_list of instance constructors, methods, indexers and delegates:
    • Позиционные аргументы, где происходит фиксированный параметр в той же позиции в списке параметров соответствует этому параметру.A positional argument where a fixed parameter occurs at the same position in the parameter list corresponds to that parameter.
    • Позиционный аргумент функции-члена с массивом параметров вызван в обычной форме соответствует в массив параметров, который должен находиться в той же позиции в списке параметров.A positional argument of a function member with a parameter array invoked in its normal form corresponds to the parameter array, which must occur at the same position in the parameter list.
    • Позиционный аргумент функции-члена с массивом параметров вызывается в расширенной форме, где нет фиксированного параметра происходит в той же позиции в списке параметров, соответствующий элемент в массиве параметров.A positional argument of a function member with a parameter array invoked in its expanded form, where no fixed parameter occurs at the same position in the parameter list, corresponds to an element in the parameter array.
    • Именованный аргумент соответствует параметру с тем же именем в списке параметров.A named argument corresponds to the parameter of the same name in the parameter list.
    • Для индексаторов, при вызове set метод доступа, выражение, указанное как правый операнд оператора присваивания соответствует неявный value параметр set объявление метода доступа.For indexers, when invoking the set accessor, the expression specified as the right operand of the assignment operator corresponds to the implicit value parameter of the set accessor declaration.
  • Для свойств, при вызове get существует метода доступа — без аргументов.For properties, when invoking the get accessor there are no arguments. При вызове set метод доступа, выражение, указанное как правый операнд оператора присваивания соответствует неявный value параметр set объявление метода доступа.When invoking the set accessor, the expression specified as the right operand of the assignment operator corresponds to the implicit value parameter of the set accessor declaration.
  • Для пользовательских унарных операторов (включая преобразования) один операнд соответствует одному параметру объявления оператора.For user-defined unary operators (including conversions), the single operand corresponds to the single parameter of the operator declaration.
  • Для пользовательских бинарных операторов левый операнд соответствует первому параметру, а правый операнд соответствует значению второго параметра объявления оператора.For user-defined binary operators, the left operand corresponds to the first parameter, and the right operand corresponds to the second parameter of the operator declaration.

Вычисление во время выполнения списков аргументовRun-time evaluation of argument lists

Во время выполнения обработки вызова функции-члена (Проверка динамического разрешения перегрузки во время компиляции), выражения или ссылки на переменные из списка аргументов оцениваются в порядке слева направо, как выглядит следующим образом:During the run-time processing of a function member invocation (Compile-time checking of dynamic overload resolution), the expressions or variable references of an argument list are evaluated in order, from left to right, as follows:

  • Для параметра значения, вычисляется выражение аргумента и неявное преобразование (неявные преобразования) для соответствующего параметра типа выполняется.For a value parameter, the argument expression is evaluated and an implicit conversion (Implicit conversions) to the corresponding parameter type is performed. Результирующее значение становится начальное значение параметра в вызове функции-члена.The resulting value becomes the initial value of the value parameter in the function member invocation.
  • Для параметра ссылки или вывода вычисляется ссылка на переменную, и итоговое расположение хранилища становится место хранения, представленное параметром в вызове функции-члена.For a reference or output parameter, the variable reference is evaluated and the resulting storage location becomes the storage location represented by the parameter in the function member invocation. Если ссылка на переменную, заданной в качестве параметра ссылки или вывода является элементом массива reference_type, выполняется проверка во время выполнения, чтобы убедитесь, что тип элемента массива отличается от типа параметра.If the variable reference given as a reference or output parameter is an array element of a reference_type, a run-time check is performed to ensure that the element type of the array is identical to the type of the parameter. Если эта проверка завершается неудачно, System.ArrayTypeMismatchException возникает исключение.If this check fails, a System.ArrayTypeMismatchException is thrown.

Методов, индексаторов и конструкторы экземпляров может объявлять их крайнее правое параметр будет массивом параметров (массивы параметров).Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter array (Parameter arrays). Такие функции-члены вызываются нормальной форме или в их расширенными формами, в зависимости от того, который применяется (применимого члена функции):Such function members are invoked either in their normal form or in their expanded form depending on which is applicable (Applicable function member):

  • Когда функция-член с массивом параметров вызывается в нормальной форме, аргумент массива параметров должно быть одно выражение, которое может быть неявно преобразован (неявные преобразования) в тип массива параметров.When a function member with a parameter array is invoked in its normal form, the argument given for the parameter array must be a single expression that is implicitly convertible (Implicit conversions) to the parameter array type. В этом случае в массиве параметров выступает точно параметра значения.In this case, the parameter array acts precisely like a value parameter.
  • Когда функция-член с массивом параметров вызывается в расширенной форме, при вызове необходимо указать ноль или более позиционные аргументы для массива параметров, где каждый аргумент является выражение, которое может быть неявно преобразован (неявные преобразования) к типу элемента в массиве параметров.When a function member with a parameter array is invoked in its expanded form, the invocation must specify zero or more positional arguments for the parameter array, where each argument is an expression that is implicitly convertible (Implicit conversions) to the element type of the parameter array. В этом случае вызов создает экземпляр типа массив с длиной, соответствующей числу аргументов, инициализирует элементы экземпляра массива с заданными значениями аргументов и использует вновь созданный экземпляр массива в качестве фактического аргумент.In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument.

Из списка аргументов всегда вычисляются в порядке, в котором они написаны.The expressions of an argument list are always evaluated in the order they are written. Таким образом примерThus, the example

class Test
{
    static void F(int x, int y = -1, int z = -2) {
        System.Console.WriteLine("x = {0}, y = {1}, z = {2}", x, y, z);
    }

    static void Main() {
        int i = 0;
        F(i++, i++, i++);
        F(z: i++, x: i++);
    }
}

выводятся следующие выходные данныеproduces the output

x = 0, y = 1, z = 2
x = 4, y = -1, z = 3

Правила совместного расхождения массива (ковариацией) разрешает значение типа массива A[] чтобы ссылаться на экземпляр типа массива B[], если существует неявное преобразование ссылок из B для A.The array co-variance rules (Array covariance) permit a value of an array type A[] to be a reference to an instance of an array type B[], provided an implicit reference conversion exists from B to A. Из-за этих правил, когда элемент массива значений reference_type передается как параметр ссылки или вывода, необходимо обеспечить, что фактическим типом элемента массива идентична параметра проверки во время выполнения.Because of these rules, when an array element of a reference_type is passed as a reference or output parameter, a run-time check is required to ensure that the actual element type of the array is identical to that of the parameter. В примереIn the example

class Test
{
    static void F(ref object x) {...}

    static void Main() {
        object[] a = new object[10];
        object[] b = new string[10];
        F(ref a[0]);        // Ok
        F(ref b[1]);        // ArrayTypeMismatchException
    }
}

Второй вызов F вызывает System.ArrayTypeMismatchException исключение, так как тип фактического элемент bstring и не object.the second invocation of F causes a System.ArrayTypeMismatchException to be thrown because the actual element type of b is string and not object.

Когда функция-член с массивом параметров вызывается в расширенной форме, вызов обрабатывается точно так, как если выражение создания массива с помощью инициализатора массива (выражениях создания массива) была вставлена вокруг Расширенные параметры.When a function member with a parameter array is invoked in its expanded form, the invocation is processed exactly as if an array creation expression with an array initializer (Array creation expressions) was inserted around the expanded parameters. Например при объявленииFor example, given the declaration

void F(int x, int y, params object[] args);

следующие вызовы расширенной формы методаthe following invocations of the expanded form of the method

F(10, 20);
F(10, 20, 30, 40);
F(10, 20, 1, "hello", 3.0);

в точности соответствуютcorrespond exactly to

F(10, 20, new object[] {});
F(10, 20, new object[] {30, 40});
F(10, 20, new object[] {1, "hello", 3.0});

В частности Обратите внимание на то, что создается пустой массив, при наличии ноль аргументов, вводимых для массива параметров.In particular, note that an empty array is created when there are zero arguments given for the parameter array.

Если аргументов опущены из функции-члена с соответствующими необязательными параметрами, неявно передаются аргументов по умолчанию объявления функции-члена.When arguments are omitted from a function member with corresponding optional parameters, the default arguments of the function member declaration are implicitly passed. Так как они всегда постоянны, их оценки не влияет на порядок вычисления остальных аргументов.Because these are always constant, their evaluation will not impact the evaluation order of the remaining arguments.

Вывод типаType inference

При вызове универсального метода без указания аргументов типа, вывод типа процесс пытается определить аргументы типа для вызова.When a generic method is called without specifying type arguments, a type inference process attempts to infer type arguments for the call. Наличие вывода типа позволяет использовать более удобный синтаксис для вызова универсального метода и позволяет программисту не указывать избыточных данных о типе.The presence of type inference allows a more convenient syntax to be used for calling a generic method, and allows the programmer to avoid specifying redundant type information. Например при объявлении метода:For example, given the method declaration:

class Chooser
{
    static Random rand = new Random();

    public static T Choose<T>(T first, T second) {
        return (rand.Next(2) == 0)? first: second;
    }
}

можно вызвать Choose метод без явного указания аргумента типа:it is possible to invoke the Choose method without explicitly specifying a type argument:

int i = Chooser.Choose(5, 213);                 // Calls Choose<int>

string s = Chooser.Choose("foo", "bar");        // Calls Choose<string>

Через вывод типа, аргументы типа int и string определяются из аргументов метода.Through type inference, the type arguments int and string are determined from the arguments to the method.

Вывод типа происходит в процессе обработки привязки во время вызова метода (вызовы методов) и выполняется до вызова этапе разрешения перегрузки.Type inference occurs as part of the binding-time processing of a method invocation (Method invocations) and takes place before the overload resolution step of the invocation. Если группа конкретного метода указывается в вызове метода и аргументы типа указаны как часть вызова метода, вывод типа применяется к каждый универсальный метод, в группу методов.When a particular method group is specified in a method invocation, and no type arguments are specified as part of the method invocation, type inference is applied to each generic method in the method group. Если вывод типа завершается успешно, выводимыми аргументами типа используются для определения типов аргументов для последующего разрешения перегрузки.If type inference succeeds, then the inferred type arguments are used to determine the types of arguments for subsequent overload resolution. Если разрешение перегрузки выбирает в качестве вызов универсального метода, выведенный тип аргументы используются как фактических аргументов для вызова.If overload resolution chooses a generic method as the one to invoke, then the inferred type arguments are used as the actual type arguments for the invocation. Если не удается вывести тип для конкретного метода, этот метод не участвует в разрешении перегрузки.If type inference for a particular method fails, that method does not participate in overload resolution. Сбой определения типа, само по себе, не вызывает ошибку во время привязки.The failure of type inference, in and of itself, does not cause a binding-time error. Тем не менее оно часто ведет к ошибке во время привязки при разрешении перегрузки не удается найти применимые методы.However, it often leads to a binding-time error when overload resolution then fails to find any applicable methods.

Если предоставленное число аргументов отличается, чем число параметров в методе, затем определение немедленно завершается со сбоем.If the supplied number of arguments is different than the number of parameters in the method, then inference immediately fails. В противном случае предполагается, что универсальный метод имеет следующую сигнатуру:Otherwise, assume that the generic method has the following signature:

Tr M<X1,...,Xn>(T1 x1, ..., Tm xm)

При вызове метода формы M(E1...Em) задачей вывода типа является поиск аргументов уникальный тип S1...Sn для каждого параметра типа X1...Xn таким образом, вызов M<S1...Sn>(E1...Em) становится действительным.With a method call of the form M(E1...Em) the task of type inference is to find unique type arguments S1...Sn for each of the type parameters X1...Xn so that the call M<S1...Sn>(E1...Em) becomes valid.

Во время вывода каждый параметр типа Xi либо фиксированной к определенному типу Si или нефиксированных с связан набор границы.During the process of inference each type parameter Xi is either fixed to a particular type Si or unfixed with an associated set of bounds. Каждая граница представляет собой определенный тип T.Each of the bounds is some type T. Изначально каждая переменная типа Xi является репликой с пустой набор границ.Initially each type variable Xi is unfixed with an empty set of bounds.

Вывод типа происходит поэтапно.Type inference takes place in phases. Каждый этап попытается определить аргументы типа для дополнительные переменные типа на основании результатов предыдущего этапа.Each phase will try to infer type arguments for more type variables based on the findings of the previous phase. На первом этапе делает некоторые начальной выводы границ, тогда как второй этап исправления переменных типа для конкретных типов и дополнительно определяет границы.The first phase makes some initial inferences of bounds, whereas the second phase fixes type variables to specific types and infers further bounds. Второй этап может потребоваться повторить несколько раз.The second phase may have to be repeated a number of times.

Примечание. Тип вывода происходит не только в том случае, при вызове универсального метода.Note: Type inference takes place not only when a generic method is called. Определение типа для преобразования групп методов описан в вывод типа при преобразовании групп методов и поиск это наиболее распространенный тип набора выражений, описан в поиск это наиболее распространенный тип набора выражений.Type inference for conversion of method groups is described in Type inference for conversion of method groups and finding the best common type of a set of expressions is described in Finding the best common type of a set of expressions.

На первом этапеThe first phase

Для каждого из аргументов метода Ei:For each of the method arguments Ei:

  • Если Ei представляет собой анонимную функцию, явный вывод типа параметра (Вывод явных типов параметров) осуществляется из Ei для TiIf Ei is an anonymous function, an explicit parameter type inference (Explicit parameter type inferences) is made from Ei to Ti
  • В противном случае, если Ei с типом U и xi является параметром значения то вывод по нижней границе становится из U для Ti.Otherwise, if Ei has a type U and xi is a value parameter then a lower-bound inference is made from U to Ti.
  • В противном случае, если Ei с типом U и xiref или out параметр исключение точное определение становится из U для Ti.Otherwise, if Ei has a type U and xi is a ref or out parameter then an exact inference is made from U to Ti.
  • В противном случае — сделать вывод для этого аргумента.Otherwise, no inference is made for this argument.

Второй этапThe second phase

Второй этап выполняется следующим образом:The second phase proceeds as follows:

  • Все нефиксированных переменных типа Xi какие не поддерживают зависят от (зависимость) любой Xj исправленные (устранению).All unfixed type variables Xi which do not depend on (Dependence) any Xj are fixed (Fixing).
  • Если таких переменных типа не существует, все нефиксированных переменных типа Xi являются фиксированной для которого все указанные ниже хранения:If no such type variables exist, all unfixed type variables Xi are fixed for which all of the following hold:
    • Не существует по крайней мере один тип переменной Xj , зависящий от XiThere is at least one type variable Xj that depends on Xi
    • Xi имеет непустой набор границXi has a non-empty set of bounds
  • Если таких переменных типа не существует и все еще существуют нефиксированных переменных типа, вывод типа завершается сбоем.If no such type variables exist and there are still unfixed type variables, type inference fails.
  • В противном случае, если нет ничего нефиксированных переменных типа существует, вывод типа завершается успешно.Otherwise, if no further unfixed type variables exist, type inference succeeds.
  • В противном случае — для всех аргументов Ei с соответствующим типом параметра Ti где выходных типов (выходных типов) содержат нефиксированных переменные типа Xj , но входных типов (входных типов) этого не сделать, вывода вывод типа (вывод типа вывода ) становится из Ei для Ti.Otherwise, for all arguments Ei with corresponding parameter type Ti where the output types (Output types) contain unfixed type variables Xj but the input types (Input types) do not, an output type inference (Output type inferences) is made from Ei to Ti. Затем второй этап повторяется.Then the second phase is repeated.

Типы входных данныхInput types

Если E является группой методов или неявно типизированные анонимная функция и T — это делегат, тип или тип дерева выражения, а затем все типы параметров T являются входных типов из E с типом T.If E is a method group or implicitly typed anonymous function and T is a delegate type or expression tree type then all the parameter types of T are input types of E with type T.

Типы выходных данныхOutput types

Если E группу методов или анонимной функции и T — это делегат, тип или тип дерева выражения, то тип возвращаемого значения Tтип выходных данных E с типом T.If E is a method group or an anonymous function and T is a delegate type or expression tree type then the return type of T is an output type of E with type T.

ЗависимостьDependence

Нефиксированных переменной типа Xi напрямую зависит от переменной нефиксированных типа Xj if для некоторых аргументов Ek с типом Tk Xj происходит в тип входного из Ek с типом Tk и Xi происходит в тип выходных данных из Ek с типом Tk.An unfixed type variable Xi depends directly on an unfixed type variable Xj if for some argument Ek with type Tk Xj occurs in an input type of Ek with type Tk and Xi occurs in an output type of Ek with type Tk.

Xj зависит от Xi Если Xj напрямую зависит от Xi или, если Xi напрямую зависит от Xk и Xk зависит от Xj.Xj depends on Xi if Xj depends directly on Xi or if Xi depends directly on Xk and Xk depends on Xj. Таким образом, «зависит» является транзитивным, но не извлечение рефлексивных замыкание «напрямую зависит от».Thus "depends on" is the transitive but not reflexive closure of "depends directly on".

Вывод типа выводаOutput type inferences

Вывода вывод типа становится из выражение E для типом T следующим образом:An output type inference is made from an expression E to a type T in the following way:

  • Если E представляет собой анонимную функцию с возвращаемым типом, выводимым U (выводимого возвращаемый тип) и T — это тип делегата или тип дерева выражения с типом возвращаемого значения Tb, затем вывод по нижней границе (нижней границам) становится из U для Tb.If E is an anonymous function with inferred return type U (Inferred return type) and T is a delegate type or expression tree type with return type Tb, then a lower-bound inference (Lower-bound inferences) is made from U to Tb.
  • В противном случае, если E является группой методов и T — это тип делегата или тип дерева выражения с типами параметров T1...Tk и типом возвращаемого значения Tbи разрешение перегрузки E с типами T1...Tk дает единый метод с возвращаемым типом U, а затем вывод по нижней границе становится из U для Tb.Otherwise, if E is a method group and T is a delegate type or expression tree type with parameter types T1...Tk and return type Tb, and overload resolution of E with the types T1...Tk yields a single method with return type U, then a lower-bound inference is made from U to Tb.
  • В противном случае, если E представляет собой выражение с типом U, а затем вывод по нижней границе становится из U для T.Otherwise, if E is an expression with type U, then a lower-bound inference is made from U to T.
  • В противном случае вывод не производится.Otherwise, no inferences are made.

Вывод явных типов параметровExplicit parameter type inferences

Явный вывод типа параметра становится из выражение E для типом T следующим образом:An explicit parameter type inference is made from an expression E to a type T in the following way:

  • Если E является явным образом типизированной анонимной функцией с типами параметров U1...Uk и T — это тип делегата или тип дерева выражения с типами параметров V1...Vk затем для каждого Ui точное Вывод (точные выводы) становится из Ui для соответствующего Vi.If E is an explicitly typed anonymous function with parameter types U1...Uk and T is a delegate type or expression tree type with parameter types V1...Vk then for each Ui an exact inference (Exact inferences) is made from Ui to the corresponding Vi.

Точный выводExact inferences

Точное определение из типом U для типом V выполняется следующим образом:An exact inference from a type U to a type V is made as follows:

  • Если V является одним из нефиксированных Xi затем U добавляется к набору точное границы для Xi.If V is one of the unfixed Xi then U is added to the set of exact bounds for Xi.

  • В противном случае задает V1...Vk и U1...Uk определяются путем проверки, если применим один из следующих случаев:Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • V является типом массива V1[...] и U является типом массива U1[...] одинакового ранга кортежамV is an array type V1[...] and U is an array type U1[...] of the same rank
    • V — Это тип V1? и U является типом U1?V is the type V1? and U is the type U1?
    • V — сконструированный тип C<V1...Vk>и U — сконструированный тип C<U1...Uk>V is a constructed type C<V1...Vk>and U is a constructed type C<U1...Uk>

    Если какие-либо из этих случаев применимы затем точное определение становится из каждого Ui для соответствующего Vi.If any of these cases apply then an exact inference is made from each Ui to the corresponding Vi.

  • В противном случае вывод не производится.Otherwise no inferences are made.

Нижняя граница выводыLower-bound inferences

Объект вывод по нижней границе из типом U для типом V выполняется следующим образом:A lower-bound inference from a type U to a type V is made as follows:

  • Если V является одним из нефиксированных Xi затем U добавляется к набору нижней границы для Xi.If V is one of the unfixed Xi then U is added to the set of lower bounds for Xi.

  • В противном случае, если V — это тип V1?и U — это тип U1? то нижняя граница вывод выполняется из U1 для V1.Otherwise, if V is the type V1?and U is the type U1? then a lower bound inference is made from U1 to V1.

  • В противном случае задает U1...Uk и V1...Vk определяются путем проверки, если применим один из следующих случаев:Otherwise, sets U1...Uk and V1...Vk are determined by checking if any of the following cases apply:

    • V является типом массива V1[...] и U является типом массива U1[...] (или эффективный базовый тип которого является параметром-типом U1[...]) одинакового ранга кортежамV is an array type V1[...] and U is an array type U1[...] (or a type parameter whose effective base type is U1[...]) of the same rank

    • V является одним из IEnumerable<V1>, ICollection<V1> или IList<V1> и U является одномерным массивом U1[](или эффективный базовый тип которого является параметром-типом U1[])V is one of IEnumerable<V1>, ICollection<V1> or IList<V1> and U is a one-dimensional array type U1[](or a type parameter whose effective base type is U1[])

    • V — сконструированный тип класса, структуры, интерфейса или делегата C<V1...Vk> и есть уникальный тип C<U1...Uk> таким образом, чтобы U (или, если U является параметром типа, его эффективным базовым классом или любым членом его эффективным набором интерфейса) — идентичен, наследует от (напрямую или косвенно), или реализует (напрямую или косвенно) C<U1...Uk>.V is a constructed class, struct, interface or delegate type C<V1...Vk> and there is a unique type C<U1...Uk> such that U (or, if U is a type parameter, its effective base class or any member of its effective interface set) is identical to, inherits from (directly or indirectly), or implements (directly or indirectly) C<U1...Uk>.

      (Ограничение «уникальности» означает, что в интерфейсе вариантов C<T> {} class U: C<X>, C<Y> {}, а затем сделать вывод, при выводе из U для C<T> поскольку U1 может быть X или Y.)(The "uniqueness" restriction means that in the case interface C<T> {} class U: C<X>, C<Y> {}, then no inference is made when inferring from U to C<T> because U1 could be X or Y.)

    Если какие-либо из этих случаев применимы, а затем выполняется вывод из каждого Ui для соответствующего Vi следующим образом:If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Если Ui неизвестен быть ссылочным типом исключение точное определение выполняетсяIf Ui is not known to be a reference type then an exact inference is made
    • В противном случае, если U является типом массива то вывод по нижней границе выполняетсяOtherwise, if U is an array type then a lower-bound inference is made
    • В противном случае, если VC<V1...Vk> вывод зависит от параметра типа i й C:Otherwise, if V is C<V1...Vk> then inference depends on the i-th type parameter of C:
      • Если он является ковариантным то вывод по нижней границе выполняется.If it is covariant then a lower-bound inference is made.
      • Если он является контравариантным, а затем вывод по верхней границе выполняется.If it is contravariant then an upper-bound inference is made.
      • Если он является инвариантным исключение точное определение выполняется.If it is invariant then an exact inference is made.
  • В противном случае вывод не производится.Otherwise, no inferences are made.

Вывод верхней границыUpper-bound inferences

Вывод по верхней границе из типом U для типом V выполняется следующим образом:An upper-bound inference from a type U to a type V is made as follows:

  • Если V является одним из нефиксированных Xi затем U добавляется к набору верхней границы для Xi.If V is one of the unfixed Xi then U is added to the set of upper bounds for Xi.

  • В противном случае задает V1...Vk и U1...Uk определяются путем проверки, если применим один из следующих случаев:Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • U является типом массива U1[...] и V является типом массива V1[...] одинакового ранга кортежамU is an array type U1[...] and V is an array type V1[...] of the same rank

    • U является одним из IEnumerable<Ue>, ICollection<Ue> или IList<Ue> и V является одномерным массивом Ve[]U is one of IEnumerable<Ue>, ICollection<Ue> or IList<Ue> and V is a one-dimensional array type Ve[]

    • U — Это тип U1? и V является типом V1?U is the type U1? and V is the type V1?

    • U — сконструированный класс, структура, интерфейс или делегат типа C<U1...Uk> и V — это класс, структура, интерфейс или делегат тип, который идентичен, наследует от (напрямую или косвенно) или реализует (напрямую или косвенно) уникальный тип C<V1...Vk>U is constructed class, struct, interface or delegate type C<U1...Uk> and V is a class, struct, interface or delegate type which is identical to, inherits from (directly or indirectly), or implements (directly or indirectly) a unique type C<V1...Vk>

      (Ограничение «уникальности» означает, что если у нас есть interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}, а затем сделать вывод, при выводе из C<U1> для V<Q>.(The "uniqueness" restriction means that if we have interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}, then no inference is made when inferring from C<U1> to V<Q>. Вывод не выполняется из U1 либо X<Q> или Y<Q>.)Inferences are not made from U1 to either X<Q> or Y<Q>.)

    Если какие-либо из этих случаев применимы, а затем выполняется вывод из каждого Ui для соответствующего Vi следующим образом:If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Если Ui неизвестен быть ссылочным типом исключение точное определение выполняетсяIf Ui is not known to be a reference type then an exact inference is made
    • В противном случае, если V является типом массива элемент вывод по верхней границе выполняетсяOtherwise, if V is an array type then an upper-bound inference is made
    • В противном случае, если UC<U1...Uk> вывод зависит от параметра типа i й C:Otherwise, if U is C<U1...Uk> then inference depends on the i-th type parameter of C:
      • Если он является ковариантным типом вывод по верхней границе выполняется.If it is covariant then an upper-bound inference is made.
      • Если он является контравариантным, а затем вывод по нижней границе выполняется.If it is contravariant then a lower-bound inference is made.
      • Если он является инвариантным исключение точное определение выполняется.If it is invariant then an exact inference is made.
  • В противном случае вывод не производится.Otherwise, no inferences are made.

ИсправленияFixing

Нефиксированных переменной типа Xi с набором границ — фиксированной следующим образом:An unfixed type variable Xi with a set of bounds is fixed as follows:

  • Набор потенциальных типов Uj начинается как набор всех типов в набор границ для Xi.The set of candidate types Uj starts out as the set of all types in the set of bounds for Xi.
  • После этого будут рассмотрены каждая граница для Xi в свою очередь: Для каждого точного границы U из Xi все типы Uj которого не идентичны U удаляются из набора кандидатов.We then examine each bound for Xi in turn: For each exact bound U of Xi all types Uj which are not identical to U are removed from the candidate set. Для каждой нижней границы U из Xi все типы Uj которых является не неявное преобразование из U удаляются из набора кандидатов.For each lower bound U of Xi all types Uj to which there is not an implicit conversion from U are removed from the candidate set. Для каждой верхней границы U из Xi все типы Uj из которых является не неявное преобразование в U удаляются из набора кандидатов.For each upper bound U of Xi all types Uj from which there is not an implicit conversion to U are removed from the candidate set.
  • Если среди оставшихся типов-кандидатов Uj есть уникальный тип V из которой отсутствует неявное преобразование в все остальные типы-кандидаты, затем Xi Фиксированная V.If among the remaining candidate types Uj there is a unique type V from which there is an implicit conversion to all the other candidate types, then Xi is fixed to V.
  • В противном случае — не удается вывести тип.Otherwise, type inference fails.

Выведенный тип возвращаемого значенияInferred return type

Выведенный тип возвращаемого значения анонимная функция F используется при разрешении типа вывода и перегрузки.The inferred return type of an anonymous function F is used during type inference and overload resolution. Выведенный тип возвращаемого значения можно определить только для анонимной функции, где все параметров, либо типы известны, так как они заданы явно, предоставляются через преобразование анонимной функции или определен во время вывода типа на во внешнем универсальный вызов метода.The inferred return type can only be determined for an anonymous function where all parameter types are known, either because they are explicitly given, provided through an anonymous function conversion or inferred during type inference on an enclosing generic method invocation.

Выведен тип результата определяется следующим образом:The inferred result type is determined as follows:

  • Если тело Fвыражение с типом, то типом результата, выводимого F тип этого выражения.If the body of F is an expression that has a type, then the inferred result type of F is the type of that expression.
  • Если тело Fблок и набор выражений в блоке return инструкции с типом наиболее распространенных T (поиск это наиболее распространенный тип набора выражений), то типом результата, выводимого F является T.If the body of F is a block and the set of expressions in the block's return statements has a best common type T (Finding the best common type of a set of expressions), then the inferred result type of F is T.
  • В противном случае — тип результата не может быть определен для F.Otherwise, a result type cannot be inferred for F.

Вывести тип возвращаемого значения определяется следующим образом:The inferred return type is determined as follows:

  • Если F является асинхронной и текст F является либо выражение классифицировано как nothing (классификации выражений), или блок операторов, где нет операторов return содержат выражения, выводимые возвращаемого типа System.Threading.Tasks.TaskIf F is async and the body of F is either an expression classified as nothing (Expression classifications), or a statement block where no return statements have expressions, the inferred return type is System.Threading.Tasks.Task
  • Если F является асинхронной и имеет тип результата, выводимого T, выводимые возвращаемого типа System.Threading.Tasks.Task<T>.If F is async and has an inferred result type T, the inferred return type is System.Threading.Tasks.Task<T>.
  • Если F синхронные и имеет тип результата, выводимого T, выводимые возвращаемого типа T.If F is non-async and has an inferred result type T, the inferred return type is T.
  • В противном случае тип возвращаемого значения не может быть определен для F.Otherwise a return type cannot be inferred for F.

В качестве примера вывода типа с анонимных функций, рассмотрим Select метод расширения, объявленный в System.Linq.Enumerable класса:As an example of type inference involving anonymous functions, consider the Select extension method declared in the System.Linq.Enumerable class:

namespace System.Linq
{
    public static class Enumerable
    {
        public static IEnumerable<TResult> Select<TSource,TResult>(
            this IEnumerable<TSource> source,
            Func<TSource,TResult> selector)
        {
            foreach (TSource element in source) yield return selector(element);
        }
    }
}

При условии, что System.Linq пространство имен была импортирована с using предложение и имеется класс Customer с Name свойство типа string, Select метод может использоваться для выбора имен список клиентов:Assuming the System.Linq namespace was imported with a using clause, and given a class Customer with a Name property of type string, the Select method can be used to select the names of a list of customers:

List<Customer> customers = GetCustomerList();
IEnumerable<string> names = customers.Select(c => c.Name);

Вызов метода расширения (вызовы методов расширения) из Select обрабатывается, переписав вызова для вызова статического метода:The extension method invocation (Extension method invocations) of Select is processed by rewriting the invocation to a static method invocation:

IEnumerable<string> names = Enumerable.Select(customers, c => c.Name);

Так как аргументы типа не указаны явным образом, вывод типа позволяет определить аргументы типа.Since type arguments were not explicitly specified, type inference is used to infer the type arguments. Во-первых, customers аргумент относится к source параметра, вывод типа T быть Customer.First, the customers argument is related to the source parameter, inferring T to be Customer. С помощью анонимной функции введите вывод процесс, описанный выше, c присваивается тип Customerи выражение c.Name связана с типом возвращаемого значения selector параметра, вывод типа S быть string.Then, using the anonymous function type inference process described above, c is given type Customer, and the expression c.Name is related to the return type of the selector parameter, inferring S to be string. Таким образом вызов эквивалентенThus, the invocation is equivalent to

Sequence.Select<Customer,string>(customers, (Customer c) => c.Name)

и результат имеет тип IEnumerable<string>.and the result is of type IEnumerable<string>.

В следующем примере показано, как анонимный тип функции вывода позволяет информацию о типе для «поток» между аргументами в вызове универсального метода.The following example demonstrates how anonymous function type inference allows type information to "flow" between arguments in a generic method invocation. Если метод:Given the method:

static Z F<X,Y,Z>(X value, Func<X,Y> f1, Func<Y,Z> f2) {
    return f2(f1(value));
}

Определение типа для вызова:Type inference for the invocation:

double seconds = F("1:15:30", s => TimeSpan.Parse(s), t => t.TotalSeconds);

продолжается следующим образом. Во-первых, аргумент "1:15:30" связана с value параметра, вывод типа X быть string.proceeds as follows: First, the argument "1:15:30" is related to the value parameter, inferring X to be string. Затем, параметр первого анонимной функции, s, предоставляется выведенный тип stringи выражение TimeSpan.Parse(s) связана с типом возвращаемого значения f1, выведения Y быть System.TimeSpan.Then, the parameter of the first anonymous function, s, is given the inferred type string, and the expression TimeSpan.Parse(s) is related to the return type of f1, inferring Y to be System.TimeSpan. Наконец, параметр второй анонимной функции, t, предоставляется выведенный тип System.TimeSpanи выражение t.TotalSeconds связана с типом возвращаемого значения f2, выведения Z быть double.Finally, the parameter of the second anonymous function, t, is given the inferred type System.TimeSpan, and the expression t.TotalSeconds is related to the return type of f2, inferring Z to be double. Таким образом, результат вызова имеет тип double.Thus, the result of the invocation is of type double.

Определение типа для преобразования групп методовType inference for conversion of method groups

Как и вызовы универсальных методов, вывод типа также должен применяться при группу методов M содержащий универсальный метод, преобразуется в данный тип делегата D (преобразования групп методов).Similar to calls of generic methods, type inference must also be applied when a method group M containing a generic method is converted to a given delegate type D (Method group conversions). Данного методаGiven a method

Tr M<X1...Xn>(T1 x1 ... Tm xm)

и группа методов M присваивается тип делегата D задачей вывода типа является поиск аргументов типа S1...Sn таким образом, выражение:and the method group M being assigned to the delegate type D the task of type inference is to find type arguments S1...Sn so that the expression:

M<S1...Sn>

становится совместимый (объявления делегатов) с D.becomes compatible (Delegate declarations) with D.

В отличие от алгоритма вывода для вызовов универсального метода, в этом случае существует только аргумент типы, аргумент выражения.Unlike the type inference algorithm for generic method calls, in this case there are only argument types, no argument expressions. В частности, нет анонимных функций и тем самым устраняет потребность в нескольких этапах вывода.In particular, there are no anonymous functions and hence no need for multiple phases of inference.

Вместо этого все Xi считаются нефиксированныхи вывод по нижней границе становится из тип каждого аргумента Uj из D для соответствующего типа параметра Tj из M.Instead, all Xi are considered unfixed, and a lower-bound inference is made from each argument type Uj of D to the corresponding parameter type Tj of M. Если для любого из Xi границы не найдены, не удается вывести тип.If for any of the Xi no bounds were found, type inference fails. В противном случае все Xi являются фиксированной соответствующий Si, которой получены в результате вывода типа.Otherwise, all Xi are fixed to corresponding Si, which are the result of type inference.

Это наиболее распространенный тип набора выражений, поискFinding the best common type of a set of expressions

В некоторых случаях тип необходимо вывести для набора выражений.In some cases, a common type needs to be inferred for a set of expressions. В частности, типы элементов этих неявно типизированные массивы и типы возвращаемого значения анонимных функций с блок тел находятся таким образом.In particular, the element types of implicitly typed arrays and the return types of anonymous functions with block bodies are found in this way.

Интуитивно, исходя из набора выражений E1...Em этот вывод должен быть эквивалентен вызову методаIntuitively, given a set of expressions E1...Em this inference should be equivalent to calling a method

Tr M<X>(X x1 ... X xm)

с помощью Ei как аргументы.with the Ei as arguments.

Точнее, вывод начинается с нефиксированных переменной типа X.More precisely, the inference starts out with an unfixed type variable X. Вывод типа вывода становятся из каждого Ei для X.Output type inferences are then made from each Ei to X. Наконец X является фиксированной и в случае успеха, полученный в результате введите S является итоговый наиболее распространенным типом для выражений.Finally, X is fixed and, if successful, the resulting type S is the resulting best common type for the expressions. Если нет такого S существует, выражения содержат наиболее общий тип отсутствует.If no such S exists, the expressions have no best common type.

Разрешение перегрузкиOverload resolution

Разрешение перегрузки — это механизм времени привязки для выбора наилучший член функции для вызова при наличии списка аргументов и набора потенциальных членов функции.Overload resolution is a binding-time mechanism for selecting the best function member to invoke given an argument list and a set of candidate function members. Разрешение перегрузки выбирает функцию-член для вызова в следующих отдельных контекстах в C#:Overload resolution selects the function member to invoke in the following distinct contexts within C#:

Каждый из этих контекстов определяет набор потенциальных членов функции и список аргументов в своим уникальным способом, как подробно описывается в разделах, перечисленных выше.Each of these contexts defines the set of candidate function members and the list of arguments in its own unique way, as described in detail in the sections listed above. Например, набор кандидатов для вызова метода не включает методы, помеченные override (поиск члена), и методов в базовом классе не являются кандидатами, если применимо любой метод в производном классе ( Вызовы методов).For example, the set of candidates for a method invocation does not include methods marked override (Member lookup), and methods in a base class are not candidates if any method in a derived class is applicable (Method invocations).

После определения потенциальных членов функции и список аргументов выбора наилучшего члена функции одинаков во всех случаях:Once the candidate function members and the argument list have been identified, the selection of the best function member is the same in all cases:

  • Имея набор применимых потенциальных членов функции, лучшие функции-члена в том, что находится набор.Given the set of applicable candidate function members, the best function member in that set is located. Если набор содержит только одну функцию-член, функция-член является наилучшим членом функции.If the set contains only one function member, then that function member is the best function member. В противном случае наилучшим членом функции является функция-член, который лучше, чем все другие функции-члены по отношению к списку аргументов при условии, что каждый член функции сравнивается со всех других функций-членов с помощью правил в Наилучший член функции.Otherwise, the best function member is the one function member that is better than all other function members with respect to the given argument list, provided that each function member is compared to all other function members using the rules in Better function member. Если отсутствия ровно одну функцию-член, который лучше, чем все другие функции-члены, то вызов функции-члена является неоднозначным и возникает ошибка во время привязки.If there is not exactly one function member that is better than all other function members, then the function member invocation is ambiguous and a binding-time error occurs.

В следующих разделах описывается значение условия применимого члена функции и наилучший член функции.The following sections define the exact meanings of the terms applicable function member and better function member.

Применимый член функцииApplicable function member

Функция-член считается применимого члена функции по отношению к список аргументов A если выполняются все следующие условия:A function member is said to be an applicable function member with respect to an argument list A when all of the following are true:

  • Каждый аргумент в A соответствует параметру в объявлении функции-члена, как описано в разделе параметры соответствующий, и любой параметр, которому соответствует аргумент является необязательным параметром.Each argument in A corresponds to a parameter in the function member declaration as described in Corresponding parameters, and any parameter to which no argument corresponds is an optional parameter.
  • Для каждого аргумента в A, передача режим для аргумента параметров (т. е. значение ref, или out) идентичен режиму передачи параметра для соответствующего параметра, иFor each argument in A, the parameter passing mode of the argument (i.e., value, ref, or out) is identical to the parameter passing mode of the corresponding parameter, and
    • для параметра значение или массив параметров, неявное преобразование (неявные преобразования) существует аргумент к типу соответствующего параметра, илиfor a value parameter or a parameter array, an implicit conversion (Implicit conversions) exists from the argument to the type of the corresponding parameter, or
    • для ref или out параметра, тип аргумента отличается от типа соответствующего параметра.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter. В конце концов ref или out является псевдонимом для передаваемых аргументов.After all, a ref or out parameter is an alias for the argument passed.

Для функции-члена, который включает массив параметров если применимо, приведенных выше правил функцию-член, он считается применимо в его обычной формой.For a function member that includes a parameter array, if the function member is applicable by the above rules, it is said to be applicable in its normal form. Если функция-член, которая включает массив параметров не применим в нормальной форме, функцию-член может быть применима в его расширенной форме:If a function member that includes a parameter array is not applicable in its normal form, the function member may instead be applicable in its expanded form:

  • Расширенная форма создается путем замены массива параметров в объявлении функции-члена с нуля или больше параметров значение параметра типа элемента массива, например, число аргументов в списке аргументов A соответствует итог число параметров.The expanded form is constructed by replacing the parameter array in the function member declaration with zero or more value parameters of the element type of the parameter array such that the number of arguments in the argument list A matches the total number of parameters. Если A меньшее число аргументов, чем число основных параметров в объявлении функции-члена, расширенную форму функцию-член не может быть создан и таким образом не применяется.If A has fewer arguments than the number of fixed parameters in the function member declaration, the expanded form of the function member cannot be constructed and is thus not applicable.
  • В противном случае — расширенная форма применимо, если для каждого аргумента в A режим передачи параметра аргумента идентичен режиму передачи параметра для соответствующего параметра, иOtherwise, the expanded form is applicable if for each argument in A the parameter passing mode of the argument is identical to the parameter passing mode of the corresponding parameter, and
    • для параметра фиксированное значение или значение параметра, созданного при расширении, неявное преобразование (неявные преобразования) существует из типа аргумента в тип соответствующего параметра, илиfor a fixed value parameter or a value parameter created by the expansion, an implicit conversion (Implicit conversions) exists from the type of the argument to the type of the corresponding parameter, or
    • для ref или out параметра, тип аргумента отличается от типа соответствующего параметра.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter.

Наилучший член функцииBetter function member

В целях определения наилучшего члена функции список урезанная аргументов типа создается содержащий только сами выражения аргументов в порядке их следования в исходном списке аргументов.For the purposes of determining the better function member, a stripped-down argument list A is constructed containing just the argument expressions themselves in the order they appear in the original argument list.

Списки параметров для каждого кандидата функции-члена формируется следующим образом:Parameter lists for each of the candidate function members are constructed in the following way:

  • Расширенная форма используется в том случае, если функция-член была применимо только в расширенной форме.The expanded form is used if the function member was applicable only in the expanded form.
  • Необязательные параметры без соответствующих аргументов удаляются из списка параметровOptional parameters with no corresponding arguments are removed from the parameter list
  • Параметры переупорядочиваются, чтобы они встречаются в той же позиции, что соответствующий аргумент в списке аргументов.The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.

Получает список аргументов A с набором выражений аргумента {E1, E2, ..., En} и два применимых члена функции Mp и Mq с типами параметров {P1, P2, ..., Pn} и {Q1, Q2, ..., Qn}, Mp определяется как наилучший член функции чем Mq ЕслиGiven an argument list A with a set of argument expressions {E1, E2, ..., En} and two applicable function members Mp and Mq with parameter types {P1, P2, ..., Pn} and {Q1, Q2, ..., Qn}, Mp is defined to be a better function member than Mq if

  • для каждого аргумента неявное преобразование из Ex для Qx не лучше, чем неявное преобразование из Ex для Px, иfor each argument, the implicit conversion from Ex to Qx is not better than the implicit conversion from Ex to Px, and
  • для по крайней мере один аргумент, преобразование из Ex для Px лучше, чем преобразование из Ex для Qx.for at least one argument, the conversion from Ex to Px is better than the conversion from Ex to Qx.

При проведении этой оценки, в том случае, если Mp или Mq применима в расширенной форме, затем Px или Qx ссылается на параметр в расширенной форме списка параметров.When performing this evaluation, if Mp or Mq is applicable in its expanded form, then Px or Qx refers to a parameter in the expanded form of the parameter list.

В случае, если параметр типа последовательности {P1, P2, ..., Pn} и {Q1, Q2, ..., Qn} эквивалентны (т. е. каждый Pi имеет преобразование удостоверения в соответствующий Qi), применяются следующие правила разрешения ничьих, в порядке, чтобы определить, тем лучше функция-член.In case the parameter type sequences {P1, P2, ..., Pn} and {Q1, Q2, ..., Qn} are equivalent (i.e. each Pi has an identity conversion to the corresponding Qi), the following tie-breaking rules are applied, in order, to determine the better function member.

  • Если Mp — это метод, не являющегося универсальным и Mq является универсальным методом, затем Mp лучше, чем Mq.If Mp is a non-generic method and Mq is a generic method, then Mp is better than Mq.
  • В противном случае, если Mp применима в нормальной форме и Mq имеет params массива и применяется только в расширенной форме, затем Mp лучше, чем Mq.Otherwise, if Mp is applicable in its normal form and Mq has a params array and is applicable only in its expanded form, then Mp is better than Mq.
  • В противном случае, если Mp объявил ли несколько параметров, чем Mq, затем Mp лучше, чем Mq.Otherwise, if Mp has more declared parameters than Mq, then Mp is better than Mq. Это может произойти, если оба метода имеют params массивов того на них применимо только в расширенных формах.This can occur if both methods have params arrays and are applicable only in their expanded forms.
  • В противном случае если все параметры Mp есть соответствующий аргумент, тогда как аргументы по умолчанию должны быть заменены для по крайней мере один необязательный параметр в Mq затем Mp лучше, чем Mq.Otherwise if all parameters of Mp have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in Mq then Mp is better than Mq.
  • В противном случае, если Mp имеет более конкретные типы параметров, чем Mq, затем Mp лучше, чем Mq.Otherwise, if Mp has more specific parameter types than Mq, then Mp is better than Mq. Позвольте {R1, R2, ..., Rn} и {S1, S2, ..., Sn} представляют типы параметров, у которого отсутствуют экземпляры и нерасширенных Mp и Mq.Let {R1, R2, ..., Rn} and {S1, S2, ..., Sn} represent the uninstantiated and unexpanded parameter types of Mp and Mq. Mpв типы параметров: более специфичен, чем MqЕсли для каждого параметра Rx не менее точно, чем Sxи по крайней мере один параметр Rx более специфичен, чем Sx:Mp's parameter types are more specific than Mq's if, for each parameter, Rx is not less specific than Sx, and, for at least one parameter, Rx is more specific than Sx:
    • Параметр типа является менее точно, чем не являющегося типом параметра.A type parameter is less specific than a non-type parameter.
    • Рекурсивно, сконструированный тип является более точным, чем другой сконструированный тип (с одинаковым числом аргументов типа) Если хотя бы один аргумент типа является более точным и менее точно, чем соответствующий аргумент типа в другой аргумент типа.Recursively, a constructed type is more specific than another constructed type (with the same number of type arguments) if at least one type argument is more specific and no type argument is less specific than the corresponding type argument in the other.
    • Тип массива указывается более специфичен, чем другой тип массива (с таким же числом измерений), если точнее, чем тип элементов второй тип первого элемента.An array type is more specific than another array type (with the same number of dimensions) if the element type of the first is more specific than the element type of the second.
  • В противном случае если один член — это оператор не удален, а другой — то оператор, лучше один не удален.Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better.
  • В противном случае лучше подходящую функцию-член.Otherwise, neither function member is better.

Лучшее преобразование из выраженияBetter conversion from expression

Неявного преобразования C1 , преобразующий из выражения E к типу T1и неявное преобразование C2 , преобразующий из выражения E к типу T2, C1лучше преобразования чем C2 Если E полностью соответствует T2 и содержит по крайней мере одно из следующих:Given an implicit conversion C1 that converts from an expression E to a type T1, and an implicit conversion C2 that converts from an expression E to a type T2, C1 is a better conversion than C2 if E does not exactly match T2 and at least one of the following holds:

Точно соответствующее выражениеExactly matching Expression

Если выражение E и типом T, E точности соответствует T Если справедливо одно из следующих условий:Given an expression E and a type T, E exactly matches T if one of the following holds:

  • E имеет тип S, и существует преобразование удостоверения из S для TE has a type S, and an identity conversion exists from S to T
  • E представляет собой анонимную функцию, T является типом делегата D или тип дерева выражения Expression<D> и содержит одно из следующих:E is an anonymous function, T is either a delegate type D or an expression tree type Expression<D> and one of the following holds:
    • Выведенный тип возвращаемого значения X существует для E в контексте в список параметров D (выводимого возвращаемый тип), и существует преобразование удостоверения из X в тип возвращаемого значения DAn inferred return type X exists for E in the context of the parameter list of D (Inferred return type), and an identity conversion exists from X to the return type of D
    • Либо E является синхронные и D с типом возврата Y или E является асинхронной и D с типом возврата Task<Y>, и содержит одно из следующих:Either E is non-async and D has a return type Y or E is async and D has a return type Task<Y>, and one of the following holds:
      • Тело E представляет собой выражение, в точности соответствующего YThe body of E is an expression that exactly matches Y
      • Тело E — это блок операторов, где каждый оператор return Возвращает выражение, в точности соответствующего YThe body of E is a statement block where every return statement returns an expression that exactly matches Y

Лучшая цель для преобразованияBetter conversion target

Учитывая два разных типа T1 и T2, T1 является целью преобразования, лучше, чем T2 Если неявное преобразование из T2 для T1 существует, и содержит по крайней мере одно из следующих:Given two different types T1 and T2, T1 is a better conversion target than T2 if no implicit conversion from T2 to T1 exists, and at least one of the following holds:

  • Неявное преобразование из T1 для T2 существуетAn implicit conversion from T1 to T2 exists
  • T1 является типом делегата D1 или тип дерева выражения Expression<D1>, T2 является типом делегата D2 или тип дерева выражения Expression<D2>, D1 с типом возврата S1 и одну из содержит следующие:T1 is either a delegate type D1 or an expression tree type Expression<D1>, T2 is either a delegate type D2 or an expression tree type Expression<D2>, D1 has a return type S1 and one of the following holds:
    • D2 Возвращает ли voidD2 is void returning
    • D2 имеет тип возвращаемого значения S2, и S1 является целью преобразования, лучше, чем S2D2 has a return type S2, and S1 is a better conversion target than S2
  • T1Task<S1>, T2Task<S2>, и S1 является целью преобразования, лучше, чем S2T1 is Task<S1>, T2 is Task<S2>, and S1 is a better conversion target than S2
  • T1S1 или S1? где S1 является целочисленным типом со знаком, и T2S2 или S2? где S2 является целочисленным типом без знака.T1 is S1 or S1? where S1 is a signed integral type, and T2 is S2 or S2? where S2 is an unsigned integral type. В частности:Specifically:
    • S1sbyte и S2byte, ushort, uint, или ulongS1 is sbyte and S2 is byte, ushort, uint, or ulong
    • S1short и S2ushort, uint, или ulongS1 is short and S2 is ushort, uint, or ulong
    • S1int и S2 является uint, или ulongS1 is int and S2 is uint, or ulong
    • S1long и S2ulongS1 is long and S2 is ulong

Перегрузка в универсальных классахOverloading in generic classes

Хотя сигнатуры при объявлении должно быть уникальным, вполне возможно, что подстановки аргументов типа приводит к одинаковые сигнатуры.While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. В таких случаях конечные правила разрешения перегрузки выше выберет конкретный член.In such cases, the tie-breaking rules of overload resolution above will pick the most specific member.

Ниже приведены примеры допустимых и недопустимых согласно этому правилу перегрузки.The following examples show overloads that are valid and invalid according to this rule:

interface I1<T> {...}

interface I2<T> {...}

class G1<U>
{
    int F1(U u);                  // Overload resolution for G<int>.F1
    int F1(int i);                // will pick non-generic

    void F2(I1<U> a);             // Valid overload
    void F2(I2<U> a);
}

class G2<U,V>
{
    void F3(U u, V v);            // Valid, but overload resolution for
    void F3(V v, U u);            // G2<int,int>.F3 will fail

    void F4(U u, I1<V> v);        // Valid, but overload resolution for    
    void F4(I1<V> v, U u);        // G2<I1<int>,int>.F4 will fail

    void F5(U u1, I1<V> v2);      // Valid overload
    void F5(V v1, U u2);

    void F6(ref U u);             // valid overload
    void F6(out V v);
}

Проверка динамического разрешения перегрузки во время компиляцииCompile-time checking of dynamic overload resolution

Для наиболее динамически связанных операций набор возможных кандидатов для разрешения во время компиляции неизвестен.For most dynamically bound operations the set of possible candidates for resolution is unknown at compile-time. В некоторых случаях Однако набор кандидатов известен во время компиляции:In certain cases, however the candidate set is known at compile-time:

  • Вызовов статических методов с динамическими аргументамиStatic method calls with dynamic arguments
  • Вызовы методов экземпляра, когда получатель не является динамическим выражениемInstance method calls where the receiver is not a dynamic expression
  • Вызовы индексатора, когда получатель не является динамическим выражениемIndexer calls where the receiver is not a dynamic expression
  • Вызовы конструктора с динамическими аргументамиConstructor calls with dynamic arguments

В таких случаях проверку только во время компиляции выполняется для каждого кандидата см. в разделе, если любой из них возможно применить во время выполнения. Эта проверка состоит из следующих действий:In these cases a limited compile-time check is performed for each candidate to see if any of them could possibly apply at run-time.This check consists of the following steps:

  • Определение разделяемого типа: Любой тип, аргумент, который не зависит от прямо или косвенно аргумент типа dynamic определяется с помощью правил вывод типа.Partial type inference: Any type argument that does not depend directly or indirectly on an argument of type dynamic is inferred using the rules of Type inference. Остальные аргументы типа неизвестны.The remaining type arguments are unknown.
  • Частичная проверка: Применимость проверяется в соответствии с применимого члена функции, но параметры, типы которых неизвестны.Partial applicability check: Applicability is checked according to Applicable function member, but ignoring parameters whose types are unknown.
  • Если нет кандидата проходит этот тест, возникает ошибка времени компиляции.If no candidate passes this test, a compile-time error occurs.

Вызов функции-членаFunction member invocation

В этом разделе описывается процесс, который происходит во время выполнения для вызова определенной функции-члена.This section describes the process that takes place at run-time to invoke a particular function member. Предполагается, что во время компиляции уже определил конкретный член для вызова, возможно, применив разрешения перегрузки для набора потенциальных членов функции.It is assumed that a binding-time process has already determined the particular member to invoke, possibly by applying overload resolution to a set of candidate function members.

В целях описания процесса вызова функции-члены можно разделить на две категории:For purposes of describing the invocation process, function members are divided into two categories:

  • Статические функции-члены.Static function members. Это конструкторы экземпляров, статические методы, статическим свойствам и определяемые пользователем операторы.These are instance constructors, static methods, static property accessors, and user-defined operators. Статические функции-члены всегда не являются виртуальными.Static function members are always non-virtual.
  • Функции-члены экземпляра.Instance function members. Это методы экземпляра, экземпляр доступа к свойствам и методам доступа индексаторов.These are instance methods, instance property accessors, and indexer accessors. Экземпляр функции-члены как физическую, так и виртуальным и всегда вызываются для конкретного экземпляра.Instance function members are either non-virtual or virtual, and are always invoked on a particular instance. Экземпляр вычисляется выражение экземпляра, и он станет доступным в функции-члена с this (такой доступ).The instance is computed by an instance expression, and it becomes accessible within the function member as this (This access).

Во время выполнения обработки вызова функции-члена состоит из следующих действий, где M является функцией-членом и, если M является членом экземпляра, E выражение экземпляра:The run-time processing of a function member invocation consists of the following steps, where M is the function member and, if M is an instance member, E is the instance expression:

  • Если M является статической функцией-членом:If M is a static function member:

  • Если M объявляется в функции-члене экземпляра value_type:If M is an instance function member declared in a value_type:

    • E выполняется оценка.E is evaluated. Если эта оценка вызывает исключение, никакие дополнительные действия выполняются.If this evaluation causes an exception, then no further steps are executed.
    • Если E не классифицируется как переменная, а затем временные локальную переменную с Eэлемента создается тип и значение E присваивается этой переменной.If E is not classified as a variable, then a temporary local variable of E's type is created and the value of E is assigned to that variable. E затем реклассифицировать как ссылку на временный локальная переменная.E is then reclassified as a reference to that temporary local variable. Временная переменная доступна в виде this в M, но не в любом другом.The temporary variable is accessible as this within M, but not in any other way. Таким образом, только если E является true переменной является возможным для вызывающего объекта увидеть изменения, M вносит this.Thus, only when E is a true variable is it possible for the caller to observe the changes that M makes to this.
    • Список аргументов вычисляется, как описано в разделе списки аргументов.The argument list is evaluated as described in Argument lists.
    • M вызывается.M is invoked. Переменная ссылается E становится ссылается переменная this.The variable referenced by E becomes the variable referenced by this.
  • Если M объявляется в функции-члене экземпляра reference_type:If M is an instance function member declared in a reference_type:

    • E выполняется оценка.E is evaluated. Если эта оценка вызывает исключение, никакие дополнительные действия выполняются.If this evaluation causes an exception, then no further steps are executed.
    • Список аргументов вычисляется, как описано в разделе списки аргументов.The argument list is evaluated as described in Argument lists.
    • Если тип Evalue_type, упаковка-преобразование (осуществлять преобразования-упаковки) выполняется, чтобы преобразовать E ввода object, и E считается Тип object в следующих шагах.If the type of E is a value_type, a boxing conversion (Boxing conversions) is performed to convert E to type object, and E is considered to be of type object in the following steps. В этом случае M может быть только членом System.Object.In this case, M could only be a member of System.Object.
    • Значение E проверяется, чтобы быть допустимыми.The value of E is checked to be valid. Если значение Enull, System.NullReferenceException возникает исключение и никакие дополнительные действия не выполняются.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • Реализация функции-члена для вызова определяется:The function member implementation to invoke is determined:
      • Если тип времени привязки E является интерфейсом, функция-член является реализацией M предоставляемые типом времени выполнения экземпляра ссылается E.If the binding-time type of E is an interface, the function member to invoke is the implementation of M provided by the run-time type of the instance referenced by E. Эта функция-член определяется применением правил сопоставления интерфейса (сопоставление интерфейса) для определения реализации M предоставляемые типом времени выполнения экземпляра ссылается E.This function member is determined by applying the interface mapping rules (Interface mapping) to determine the implementation of M provided by the run-time type of the instance referenced by E.
      • В противном случае, если M входит виртуальная функция, вызываемая функция-член является реализацией M предоставляемые типом времени выполнения экземпляра, на который указывает E.Otherwise, if M is a virtual function member, the function member to invoke is the implementation of M provided by the run-time type of the instance referenced by E. Эта функция-член определяется применением правил для определения наиболее производной реализацией (виртуальных методов) из M по отношению к времени выполнения тип экземпляра, E.This function member is determined by applying the rules for determining the most derived implementation (Virtual methods) of M with respect to the run-time type of the instance referenced by E.
      • В противном случае M является членом невиртуальной функции, а функция-член для вызова M сам.Otherwise, M is a non-virtual function member, and the function member to invoke is M itself.
    • Вызывается реализация функции-члена, определенный на предыдущем шаге.The function member implementation determined in the step above is invoked. Объект, упоминаемый в E становится объект, упоминаемый в this.The object referenced by E becomes the object referenced by this.

Вызов в упакованных экземплярахInvocations on boxed instances

Функция-член реализуется в value_type можно вызывать с помощью упакованный экземпляр, value_type в следующих ситуациях:A function member implemented in a value_type can be invoked through a boxed instance of that value_type in the following situations:

  • Если функция-член имеет override метода, унаследованного от типа object и вызывается через выражение экземпляра типа object.When the function member is an override of a method inherited from type object and is invoked through an instance expression of type object.
  • Когда функция-член представляет собой реализацию функции-члена и вызывается через выражение экземпляра interface_type.When the function member is an implementation of an interface function member and is invoked through an instance expression of an interface_type.
  • Когда функция-член вызывается через делегат.When the function member is invoked through a delegate.

В таких ситуациях упакованный экземпляр считается содержит переменную value_type, и эта переменная становится ссылается переменная this в вызове функции-члена.In these situations, the boxed instance is considered to contain a variable of the value_type, and this variable becomes the variable referenced by this within the function member invocation. В частности это означает, что при вызове функции-члена на упакованный экземпляр возможна функцию-член изменить значение, содержащееся в упакованный экземпляр.In particular, this means that when a function member is invoked on a boxed instance, it is possible for the function member to modify the value contained in the boxed instance.

Основные выраженияPrimary expressions

Первичные выражения включают простые формы выражений.Primary expressions include the simplest forms of expressions.

primary_expression
    : primary_no_array_creation_expression
    | array_creation_expression
    ;

primary_no_array_creation_expression
    : literal
    | interpolated_string_expression
    | simple_name
    | parenthesized_expression
    | member_access
    | invocation_expression
    | element_access
    | this_access
    | base_access
    | post_increment_expression
    | post_decrement_expression
    | object_creation_expression
    | delegate_creation_expression
    | anonymous_object_creation_expression
    | typeof_expression
    | checked_expression
    | unchecked_expression
    | default_value_expression
    | nameof_expression
    | anonymous_method_expression
    | primary_no_array_creation_expression_unsafe
    ;

Первичные выражения разделяются между array_creation_expressions и primary_no_array_creation_expressions.Primary expressions are divided between array_creation_expressions and primary_no_array_creation_expressions. Рассматривая выражение создания массива таким образом, вместо того чтобы, добавив его вместе с других форм простое выражение, позволяет в грамматике запретить может ввести в заблуждение кода, такие какTreating array-creation-expression in this way, rather than listing it along with the other simple expression forms, enables the grammar to disallow potentially confusing code such as

object o = new int[3][1];

который в противном случае будет интерпретироваться какwhich would otherwise be interpreted as

object o = (new int[3])[1];

ЛитералыLiterals

Объект primary_expression , состоящий из литерала (литералы) классифицируется как значение.A primary_expression that consists of a literal (Literals) is classified as a value.

Интерполированные строкиInterpolated strings

Interpolated_string_expression состоит из $ входа следуют обычный или буквального строкового литерала, при котором бреши в системе, разделяемых строками { и }, заключите выражения и форматирование спецификации.An interpolated_string_expression consists of a $ sign followed by a regular or verbatim string literal, wherein holes, delimited by { and }, enclose expressions and formatting specifications. Интерполированное строковое выражение является результатом interpolated_string_literal , был разбит на отдельные части, как описано в разделе интерполированные строковые литералы.An interpolated string expression is the result of an interpolated_string_literal that has been broken up into individual tokens, as described in Interpolated string literals.

interpolated_string_expression
    : '$' interpolated_regular_string
    | '$' interpolated_verbatim_string
    ;

interpolated_regular_string
    : interpolated_regular_string_whole
    | interpolated_regular_string_start interpolated_regular_string_body interpolated_regular_string_end
    ;

interpolated_regular_string_body
    : interpolation (interpolated_regular_string_mid interpolation)*
    ;

interpolation
    : expression
    | expression ',' constant_expression
    ;

interpolated_verbatim_string
    : interpolated_verbatim_string_whole
    | interpolated_verbatim_string_start interpolated_verbatim_string_body interpolated_verbatim_string_end
    ;

interpolated_verbatim_string_body
    : interpolation (interpolated_verbatim_string_mid interpolation)+
    ;

Constant_expression интерполяции должен иметь неявное преобразование в int.The constant_expression in an interpolation must have an implicit conversion to int.

Interpolated_string_expression классифицируется как значение.An interpolated_string_expression is classified as a value. Если сразу же он преобразуется в System.IFormattable или System.FormattableString с преобразование неявных интерполированной строки (неявные интерполированные преобразования строк), интерполированного строкового выражения имеет этот тип.If it is immediately converted to System.IFormattable or System.FormattableString with an implicit interpolated string conversion (Implicit interpolated string conversions), the interpolated string expression has that type. В противном случае он имеет тип string.Otherwise, it has the type string.

Если тип интерполированной строки System.IFormattable или System.FormattableString, значение представляет собой вызов System.Runtime.CompilerServices.FormattableStringFactory.Create.If the type of an interpolated string is System.IFormattable or System.FormattableString, the meaning is a call to System.Runtime.CompilerServices.FormattableStringFactory.Create. Если тип является string, значение выражения представляет собой вызов string.Format.If the type is string, the meaning of the expression is a call to string.Format. В обоих случаях списке аргументов вызова состоит из строковый литерал с заполнителями для каждого интерполяции и аргумент для каждого выражения, соответствующего заполнители формата.In both cases, the argument list of the call consists of a format string literal with placeholders for each interpolation, and an argument for each expression corresponding to the place holders.

Формат строкового литерала составляется следующим образом, где N число интерполяции в interpolated_string_expression:The format string literal is constructed as follows, where N is the number of interpolations in the interpolated_string_expression:

  • Если interpolated_regular_string_whole или interpolated_verbatim_string_whole соответствует $ подписать, строковый литерал формата, то этот маркер.If an interpolated_regular_string_whole or an interpolated_verbatim_string_whole follows the $ sign, then the format string literal is that token.
  • В противном случае формат строковый литерал состоит из:Otherwise, the format string literal consists of:
    • Первый interpolated_regular_string_start или interpolated_verbatim_string_startFirst the interpolated_regular_string_start or interpolated_verbatim_string_start
    • Затем для каждого номера I из 0 для N-1:Then for each number I from 0 to N-1:
      • Десятичное представление IThe decimal representation of I
      • Затем, если соответствующий интерполяции имеет constant_expression, , (запятая) следуют десятичное представление значение constant_expressionThen, if the corresponding interpolation has a constant_expression, a , (comma) followed by the decimal representation of the value of the constant_expression
      • Затем interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid или interpolated_ verbatim_string_end сразу после соответствующего интерполяции.Then the interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid or interpolated_verbatim_string_end immediately following the corresponding interpolation.

Последующие аргументы представляют собой выражения из интерполяций (если таковые имеются), в порядке.The subsequent arguments are simply the expressions from the interpolations (if any), in order.

TODO: примеры.TODO: examples.

Простые именаSimple names

Объект simple_name состоит из идентификатора, необязательно следует список аргументов типа:A simple_name consists of an identifier, optionally followed by a type argument list:

simple_name
    : identifier type_argument_list?
    ;

Объект simple_name либо формы I или формы I<A1,...,Ak>, где I — отдельный идентификатор и <A1,...,Ak> не является обязательной type_argument_list.A simple_name is either of the form I or of the form I<A1,...,Ak>, where I is a single identifier and <A1,...,Ak> is an optional type_argument_list. Если аргумент type_argument_list будет указано, рассмотрите возможность K должно быть равно нулю.When no type_argument_list is specified, consider K to be zero. Simple_name вычисляется и классифицируется следующим образом:The simple_name is evaluated and classified as follows:

  • Если K равно нулю и simple_name отображается в блок и, если блокэлемента (или во внешнем блокв) локальный объявление переменной пространства (объявления) содержит локальную переменную, параметр или константа с именем I, а затем simple_name ссылается локальная переменная, параметр или константа и классифицируется как переменная или значение.If K is zero and the simple_name appears within a block and if the block's (or an enclosing block's) local variable declaration space (Declarations) contains a local variable, parameter or constant with name I, then the simple_name refers to that local variable, parameter or constant and is classified as a variable or value.

  • Если K равно нулю и simple_name отображается в основном тексте, входящем в объявление универсального метода и если это объявление включает параметр типа с именем I, а затем simple_nameссылается на этот параметр типа.If K is zero and the simple_name appears within the body of a generic method declaration and if that declaration includes a type parameter with name I, then the simple_name refers to that type parameter.

  • В противном случае — для каждого типа экземпляра T (тип экземпляра), начиная с типом экземпляра немедленно включающего объявления типа и продолжить с типом экземпляра каждого включающего класса или структуры объявления (при его наличии):Otherwise, for each instance type T (The instance type), starting with the instance type of the immediately enclosing type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):

    • Если K равно нулю и объявление T включает параметр типа с именем I, а затем simple_name ссылается на этот параметр типа.If K is zero and the declaration of T includes a type parameter with name I, then the simple_name refers to that type parameter.
    • В противном случае, если поиск члена (поиск члена) из I в T с K  аргументы типа найдено соответствие:Otherwise, if a member lookup (Member lookup) of I in T with K type arguments produces a match:
      • Если T является тип экземпляра немедленно включающего типа класса или структуры и уточняющего запроса определяет одну или несколько методов, результат — это группа методов со связанным выражением экземпляра this.If T is the instance type of the immediately enclosing class or struct type and the lookup identifies one or more methods, the result is a method group with an associated instance expression of this. Если указан список аргументов типа, он используется в вызове универсального метода (вызовы методов).If a type argument list was specified, it is used in calling a generic method (Method invocations).
      • В противном случае, если T не тип экземпляра немедленно включающего типа класса или структуры, в том случае, если уточняющего запроса определяет член экземпляра, и в том случае, если возникает в теле конструктора экземпляра, методе экземпляра или метода доступа к экземпляру Результатом является таким же, как доступ к члену (доступ к членам) формы this.I.Otherwise, if T is the instance type of the immediately enclosing class or struct type, if the lookup identifies an instance member, and if the reference occurs within the body of an instance constructor, an instance method, or an instance accessor, the result is the same as a member access (Member access) of the form this.I. Это может произойти, только когда K равно нулю.This can only happen when K is zero.
      • В противном случае результат является таким же, как доступ к члену (доступ к членам) формы T.I или T.I<A1,...,Ak>.Otherwise, the result is the same as a member access (Member access) of the form T.I or T.I<A1,...,Ak>. В этом случае является ошибкой времени привязки для simple_name для ссылки на член экземпляра.In this case, it is a binding-time error for the simple_name to refer to an instance member.
  • В противном случае — для каждого пространства имен N, начиная с пространством имен, в котором simple_name происходит, продолжая каждого включающего пространства имен (если таковые имеются) и заканчивая глобальное пространство имен, выполнив следующие действия вычисления, пока не будет обнаружена сущность:Otherwise, for each namespace N, starting with the namespace in which the simple_name occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:

    • Если K равно нулю и I имя пространства имен в N, затем:If K is zero and I is the name of a namespace in N, then:
      • Если расположение где simple_name происходит заключен в объявление пространства имен для N и содержит объявление пространства имен extern_alias_directive или using_alias_directive , связывает имя I пространства имен или тип, а затем simple_name является неоднозначным и возникает ошибка времени компиляции.If the location where the simple_name occurs is enclosed by a namespace declaration for N and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with a namespace or type, then the simple_name is ambiguous and a compile-time error occurs.
      • В противном случае simple_name ссылается на пространство имен с именем I в N.Otherwise, the simple_name refers to the namespace named I in N.
    • В противном случае, если N содержит доступный тип с именем I и K  параметрами типа, то:Otherwise, if N contains an accessible type having name I and K type parameters, then:
      • Если K равно нулю и расположение где simple_name происходит заключен в объявление пространства имен для N и содержит объявление пространства имен extern_alias_directiveили using_alias_directive , связывает имя I пространства имен или тип, а затем simple_name является неоднозначным и возникает ошибка времени компиляции.If K is zero and the location where the simple_name occurs is enclosed by a namespace declaration for N and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with a namespace or type, then the simple_name is ambiguous and a compile-time error occurs.
      • В противном случае namespace_or_type_name ссылается на тип, сформированный с заданными аргументами типа.Otherwise, the namespace_or_type_name refers to the type constructed with the given type arguments.
    • В противном случае, если расположение где simple_name происходит заключен в объявление пространства имен для N:Otherwise, if the location where the simple_name occurs is enclosed by a namespace declaration for N:
      • Если K равен нулю и содержит объявление пространства имен extern_alias_directive или using_alias_directive , связывает имя I с импортированное пространство имен или тип, а затем simple_name ссылается на это пространство имен или тип.If K is zero and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with an imported namespace or type, then the simple_name refers to that namespace or type.
      • В противном случае, если объявления типов и пространств имен, импортированные с using_namespace_directives и using_static_directiveобъявления пространства имен содержат ровно один доступный тип или не являющийся расширением статический член, имеющий имя I и K  параметры типа, а затем simple_name ссылается на этот тип или член, сформированный с заданными аргументами типа.Otherwise, if the namespaces and type declarations imported by the using_namespace_directives and using_static_directives of the namespace declaration contain exactly one accessible type or non-extension static member having name I and K type parameters, then the simple_name refers to that type or member constructed with the given type arguments.
      • В противном случае, если пространства имен и типы, импортированные с using_namespace_directiveобъявления пространства имен содержат более чем один доступный тип или расширение метод статический член, имеющий имя I и K  параметры типа, а затем simple_name является неоднозначным и возникает ошибка.Otherwise, if the namespaces and types imported by the using_namespace_directives of the namespace declaration contain more than one accessible type or non-extension-method static member having name I and K type parameters, then the simple_name is ambiguous and an error occurs.

    Обратите внимание, что этот этап полностью повторяет соответствующий шаг в обработке namespace_or_type_name (пространства имен и тип).Note that this entire step is exactly parallel to the corresponding step in the processing of a namespace_or_type_name (Namespace and type names).

  • В противном случае simple_name — не определено и возникает ошибка времени компиляции.Otherwise, the simple_name is undefined and a compile-time error occurs.

Выражения в скобкахParenthesized expressions

Объект parenthesized_expression состоит из выражение заключены в круглые скобки.A parenthesized_expression consists of an expression enclosed in parentheses.

parenthesized_expression
    : '(' expression ')'
    ;

Объект parenthesized_expression вычисляется путем вычисления выражение в круглых скобках.A parenthesized_expression is evaluated by evaluating the expression within the parentheses. Если выражение в круглых скобках обозначает пространство имен или тип, возникает ошибка времени компиляции.If the expression within the parentheses denotes a namespace or type, a compile-time error occurs. В противном случае результат parenthesized_expression является результатом вычисления содержащегося выражение.Otherwise, the result of the parenthesized_expression is the result of the evaluation of the contained expression.

Доступ к членамMember access

Объект member_access состоит из primary_expression, predefined_type, или qualified_alias_member, а затем«."токена, за которым следует идентификатор, при необходимости за которым следует type_argument_list.A member_access consists of a primary_expression, a predefined_type, or a qualified_alias_member, followed by a "." token, followed by an identifier, optionally followed by a type_argument_list.

member_access
    : primary_expression '.' identifier type_argument_list?
    | predefined_type '.' identifier type_argument_list?
    | qualified_alias_member '.' identifier
    ;

predefined_type
    : 'bool'   | 'byte'  | 'char'  | 'decimal' | 'double' | 'float' | 'int' | 'long'
    | 'object' | 'sbyte' | 'short' | 'string'  | 'uint'   | 'ulong' | 'ushort'
    ;

Qualified_alias_member рабочей определяется в Квалификаторы псевдонима пространства имен.The qualified_alias_member production is defined in Namespace alias qualifiers.

Объект member_access либо формы E.I или формы E.I<A1, ..., Ak>, где E — это основное выражение, I — отдельный идентификатор и <A1, ..., Ak> не является обязательной type_argument_list.A member_access is either of the form E.I or of the form E.I<A1, ..., Ak>, where E is a primary-expression, I is a single identifier and <A1, ..., Ak> is an optional type_argument_list. Если аргумент type_argument_list будет указано, рассмотрите возможность K должно быть равно нулю.When no type_argument_list is specified, consider K to be zero.

Объект member_access с primary_expression типа dynamic является динамическим (динамической привязки).A member_access with a primary_expression of type dynamic is dynamically bound (Dynamic binding). В этом случае компилятор классифицирует доступ к члену, как доступ к свойству типа dynamic.In this case the compiler classifies the member access as a property access of type dynamic. Правила для определения значения member_access применяются во время выполнения, используя тип времени выполнения вместо во время компиляции тип primary_expression.The rules below to determine the meaning of the member_access are then applied at run-time, using the run-time type instead of the compile-time type of the primary_expression. Если эта классификация во время выполнения приводит к группу методов, то должен быть доступ к членам primary_expression из invocation_expression.If this run-time classification leads to a method group, then the member access must be the primary_expression of an invocation_expression.

Member_access вычисляется и классифицируется следующим образом:The member_access is evaluated and classified as follows:

  • Если K равно нулю и E — это пространство имен и E содержит вложенное пространство имен с именем I, то результат этого пространства имен.If K is zero and E is a namespace and E contains a nested namespace with name I, then the result is that namespace.
  • В противном случае, если E — это пространство имен и E содержит доступный тип с именем I и K  параметры типа, то результат тоже этот тип, сформированный с заданными аргументами типа.Otherwise, if E is a namespace and E contains an accessible type having name I and K type parameters, then the result is that type constructed with the given type arguments.
  • Если Epredefined_type или primary_expression классифицируется как тип, если E не является параметром типа и при поиске элемента (поиск члена) из I в E с K  параметров типа найдено соответствие, затем E.I вычисляется и классифицируется следующим образом:If E is a predefined_type or a primary_expression classified as a type, if E is not a type parameter, and if a member lookup (Member lookup) of I in E with K type parameters produces a match, then E.I is evaluated and classified as follows:
    • Если I определяет тип, то результат тоже этот тип, сформированный с заданными аргументами типа.If I identifies a type, then the result is that type constructed with the given type arguments.
    • Если I определяет один или несколько методов, то результат тоже группу методов с без связанного выражения экземпляра.If I identifies one or more methods, then the result is a method group with no associated instance expression. Если указан список аргументов типа, он используется в вызове универсального метода (вызовы методов).If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Если I идентифицирует static свойство, то результат будет доступ к свойству без связанного экземпляра выражения.If I identifies a static property, then the result is a property access with no associated instance expression.
    • Если I идентифицирует static поля:If I identifies a static field:
      • Если поле является readonly и возникает за пределами статическом конструкторе класса или структуры, в котором объявляется поле, то результатом является значение, а именно значение статического поля I в E.If the field is readonly and the reference occurs outside the static constructor of the class or struct in which the field is declared, then the result is a value, namely the value of the static field I in E.
      • В противном случае результат является переменная, а именно статическое поле I в E.Otherwise, the result is a variable, namely the static field I in E.
    • Если I идентифицирует static событий:If I identifies a static event:
      • Если возникает внутри класса или структуры, в котором объявлено событие, и это событие было объявлено без event_accessor_declarations (события), затем E.I обрабатывается точно так, как если I были статического поля.If the reference occurs within the class or struct in which the event is declared, and the event was declared without event_accessor_declarations (Events), then E.I is processed exactly as if I were a static field.
      • В противном случае результатом является доступ к событию с без связанного выражения экземпляра.Otherwise, the result is an event access with no associated instance expression.
    • Если I определяет константу, то результатом является значение, а именно значение этой константы.If I identifies a constant, then the result is a value, namely the value of that constant.
    • Если I идентифицирует элемент перечисления, то результатом является значение, а именно значение этого члена перечисления.If I identifies an enumeration member, then the result is a value, namely the value of that enumeration member.
    • В противном случае E.I является недопустимой ссылкой на член, и возникает ошибка времени компиляции.Otherwise, E.I is an invalid member reference, and a compile-time error occurs.
  • Если E доступ к свойству, индексатору, переменная или значение, тип которого — Tи поиск члена (поиск члена) из I в T с K  аргументы типа найдено соответствие, затем E.I вычисляется и классифицируется следующим образом:If E is a property access, indexer access, variable, or value, the type of which is T, and a member lookup (Member lookup) of I in T with K type arguments produces a match, then E.I is evaluated and classified as follows:
    • Во-первых, если E свойство или индексатор, то значение свойства или получения доступа к индексатору (значения выражений) и E реклассифицировать как значение.First, if E is a property or indexer access, then the value of the property or indexer access is obtained (Values of expressions) and E is reclassified as a value.
    • Если I определяет один или несколько методов, то результатом является группа методов со связанным выражением экземпляра E.If I identifies one or more methods, then the result is a method group with an associated instance expression of E. Если указан список аргументов типа, он используется в вызове универсального метода (вызовы методов).If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Если I определяет свойство экземпляра,If I identifies an instance property,
      • Если Ethis, I определяет автоматически реализуемого свойства (автоматически реализуемые свойства) без метода задания и ссылка на происходит внутри конструктора для экземпляра тип класса или структуры T, то результатом является переменной, а именно скрытые резервное поле для автоматически свойство, заданное параметром I в экземпляре T предоставленное this.If E is this, I identifies an automatically implemented property (Automatically implemented properties) without a setter, and the reference occurs within an instance constructor for a class or struct type T, then the result is a variable, namely the hidden backing field for the auto-property given by I in the instance of T given by this.
      • В противном случае результатом является доступ к свойству со связанным выражением экземпляра E.Otherwise, the result is a property access with an associated instance expression of E.
    • Если Tclass_type и I определяет поле экземпляра, class_type:If T is a class_type and I identifies an instance field of that class_type:
      • Если значение Enull, а затем System.NullReferenceException возникает исключение.If the value of E is null, then a System.NullReferenceException is thrown.
      • В противном случае, если поле является readonly и возникает за пределами конструктора экземпляра класса, в котором объявляется поле, то результатом является значение, а именно значение поля I в объект, упоминаемый в E.Otherwise, if the field is readonly and the reference occurs outside an instance constructor of the class in which the field is declared, then the result is a value, namely the value of the field I in the object referenced by E.
      • В противном случае результат является переменная, а именно поле I в объект, упоминаемый в E.Otherwise, the result is a variable, namely the field I in the object referenced by E.
    • Если Tstruct_type и I определяет поле экземпляра, struct_type:If T is a struct_type and I identifies an instance field of that struct_type:
      • Если E является значением, или если поле является readonly и возникает за пределами конструктора экземпляра структуры, в котором объявляется поле, то результатом является значение, а именно значение поля I в экземпляре структуры  E.If E is a value, or if the field is readonly and the reference occurs outside an instance constructor of the struct in which the field is declared, then the result is a value, namely the value of the field I in the struct instance given by E.
      • В противном случае результат является переменная, а именно поле I в экземпляре структуры по E.Otherwise, the result is a variable, namely the field I in the struct instance given by E.
    • Если I обозначает событие экземпляра:If I identifies an instance event:
      • Если возникает внутри класса или структуры, в котором объявлено событие, и это событие было объявлено без event_accessor_declarations (события), и ссылки не выполняются от имени левый операнд оператора += или -= оператор, затем E.I обрабатывается точно так, как если I был полем экземпляра.If the reference occurs within the class or struct in which the event is declared, and the event was declared without event_accessor_declarations (Events), and the reference does not occur as the left-hand side of a += or -= operator, then E.I is processed exactly as if I was an instance field.
      • В противном случае результатом является доступ к событию со связанным выражением экземпляра E.Otherwise, the result is an event access with an associated instance expression of E.
  • В противном случае попытки для обработки E.I как вызов метода расширения (вызовы методов расширения).Otherwise, an attempt is made to process E.I as an extension method invocation (Extension method invocations). В случае сбоя E.I является недопустимой ссылкой на член, и возникает ошибка во время привязки.If this fails, E.I is an invalid member reference, and a binding-time error occurs.

Идентичные простые имена и имена типовIdentical simple names and type names

В доступ к члену в форме E.I, если E — отдельный идентификатор и, если значение E как simple_name (простые имена) — это константы, поля, свойства, Локальная переменная или параметр с тем же типом, что значение E как type_name (пространства имен и тип), то оба значения из E , разрешено.In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple_name (Simple names) is a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type_name (Namespace and type names), then both possible meanings of E are permitted. Два возможных значения E.I никогда не являются неоднозначными, так как I обязательно должен быть членом типа E в обоих случаях.The two possible meanings of E.I are never ambiguous, since I must necessarily be a member of the type E in both cases. Другими словами, правило просто разрешает доступ к статическим членам и вложенные типы E где во время компиляции в противном случае возникает ошибка.In other words, the rule simply permits access to the static members and nested types of E where a compile-time error would otherwise have occurred. Пример:For example:

struct Color
{
    public static readonly Color White = new Color(...);
    public static readonly Color Black = new Color(...);

    public Color Complement() {...}
}

class A
{
    public Color Color;                // Field Color of type Color

    void F() {
        Color = Color.Black;           // References Color.Black static member
        Color = Color.Complement();    // Invokes Complement() on Color field
    }

    static void G() {
        Color c = Color.White;         // References Color.White static member
    }
}

Неоднозначность грамматикиGrammar ambiguities

Порождения для simple_name (простые имена) и member_access (доступ к членам) может привести к появлению неоднозначности в Грамматика для выражений.The productions for simple_name (Simple names) and member_access (Member access) can give rise to ambiguities in the grammar for expressions. Например оператор:For example, the statement:

F(G<A,B>(7));

может быть интерпретирован как вызов F с двумя аргументами G < A и B > (7).could be interpreted as a call to F with two arguments, G < A and B > (7). Кроме того, он может быть интерпретирован как вызов F с одним аргументом, который представляет собой вызов универсального метода G с двумя аргументами типа и одним обычным аргументом.Alternatively, it could be interpreted as a call to F with one argument, which is a call to a generic method G with two type arguments and one regular argument.

Если последовательность токенов может быть проанализировано как (в контексте) simple_name (простые имена), member_access (доступ к членам), или pointer_member_access (доступа к членам указателей) заканчивается type_argument_list (аргументы типа), токен сразу после закрывающего > маркер проверяется.If a sequence of tokens can be parsed (in context) as a simple_name (Simple names), member_access (Member access), or pointer_member_access (Pointer member access) ending with a type_argument_list (Type arguments), the token immediately following the closing > token is examined. Если он является одним изIf it is one of

(  )  ]  }  :  ;  ,  .  ?  ==  !=  |  ^

затем type_argument_list сохраняется как часть simple_name, member_access или pointer_member_access , а также другой возможный разбор последовательность токенов, отбрасываются.then the type_argument_list is retained as part of the simple_name, member_access or pointer_member_access and any other possible parse of the sequence of tokens is discarded. В противном случае type_argument_list не считается частью simple_name, member_access или pointer_member_access, даже если нет других возможных синтаксического анализа последовательности маркеров.Otherwise, the type_argument_list is not considered to be part of the simple_name, member_access or pointer_member_access, even if there is no other possible parse of the sequence of tokens. Обратите внимание, что эти правила не применяются при разборе type_argument_list в namespace_or_type_name (пространства имен и тип).Note that these rules are not applied when parsing a type_argument_list in a namespace_or_type_name (Namespace and type names). ОператорThe statement

F(G<A,B>(7));

согласно этому правилу, интерпретируются как вызов F с одним аргументом, который представляет собой вызов универсального метода G с двумя аргументами типа и одним обычным аргументом.will, according to this rule, be interpreted as a call to F with one argument, which is a call to a generic method G with two type arguments and one regular argument. ОператорыThe statements

F(G < A, B > 7);
F(G < A, B >> 7);

будет интерпретирован как вызов F с двумя аргументами.will each be interpreted as a call to F with two arguments. ОператорThe statement

x = F < A > +y;

будут интерпретироваться как оператор, больше, чем оператор и унарный оператор «плюс», «меньше», как если бы выражение было записано x = (F < A) > (+y), а не как simple_name с type_argument_list следует оператор сложения двоичный файл.will be interpreted as a less than operator, greater than operator, and unary plus operator, as if the statement had been written x = (F < A) > (+y), instead of as a simple_name with a type_argument_list followed by a binary plus operator. В инструкцииIn the statement

x = y is C<T> + z;

токены C<T> интерпретируются как namespace_or_type_name с type_argument_list.the tokens C<T> are interpreted as a namespace_or_type_name with a type_argument_list.

Выражения вызоваInvocation expressions

Invocation_expression используется для вызова метода.An invocation_expression is used to invoke a method.

invocation_expression
    : primary_expression '(' argument_list? ')'
    ;

Invocation_expression является динамическим (динамической привязки) Если содержит по крайней мере одно из следующих:An invocation_expression is dynamically bound (Dynamic binding) if at least one of the following holds:

  • Primary_expression имеет тип времени компиляции dynamic.The primary_expression has compile-time type dynamic.
  • По крайней мере один аргумент в необязательный argument_list имеет тип времени компиляции dynamic и primary_expression имеет тип делегата.At least one argument of the optional argument_list has compile-time type dynamic and the primary_expression does not have a delegate type.

В этом случае компилятор классифицирует invocation_expression как значение типа dynamic.In this case the compiler classifies the invocation_expression as a value of type dynamic. Правила для определения значения invocation_expression применяются во время выполнения, используя тип времени выполнения вместо компиляции типа primary_expression и аргументы, которые имеют тип времени компиляции dynamic.The rules below to determine the meaning of the invocation_expression are then applied at run-time, using the run-time type instead of the compile-time type of those of the primary_expression and arguments which have the compile-time type dynamic. Если primary_expression не имеет типа во время компиляции dynamic, то вызов метода выполнена ограниченная проверка времени компиляции, как описано в разделе Проверка динамического разрешения перегрузки во время компиляции .If the primary_expression does not have compile-time type dynamic, then the method invocation undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.

Primary_expression из invocation_expression должно быть группой методов или значение delegate_type.The primary_expression of an invocation_expression must be a method group or a value of a delegate_type. Если primary_expression является группой методов invocation_expression вызовом метода (вызовы методов).If the primary_expression is a method group, the invocation_expression is a method invocation (Method invocations). Если primary_expression представляет собой значение delegate_type, invocation_expression является вызовом делегата (вызовыделегатов).If the primary_expression is a value of a delegate_type, the invocation_expression is a delegate invocation (Delegate invocations). Если primary_expression не является ни группу методов, ни значение delegate_type, возникает ошибка во время привязки.If the primary_expression is neither a method group nor a value of a delegate_type, a binding-time error occurs.

Необязательный argument_list (списки аргументов) предоставляет значения или ссылки на переменные для параметров метода.The optional argument_list (Argument lists) provides values or variable references for the parameters of the method.

Результат вычисления invocation_expression классифицируется следующим образом:The result of evaluating an invocation_expression is classified as follows:

  • Если invocation_expression вызывает метод или делегат, который возвращает void, ничего не возвращается.If the invocation_expression invokes a method or delegate that returns void, the result is nothing. Выражение, которое классифицируется допускается только в контексте statement_expression (операторы выражений) или в теле lambda_expression(Выражения анонимных функций).An expression that is classified as nothing is permitted only in the context of a statement_expression (Expression statements) or as the body of a lambda_expression (Anonymous function expressions). В противном случае возникает ошибка времени привязки.Otherwise a binding-time error occurs.
  • В противном случае результатом является значение типа, возвращаемого методом или делегата.Otherwise, the result is a value of the type returned by the method or delegate.

Вызовы методовMethod invocations

Для вызова метода primary_expression из invocation_expression должно быть группой методов.For a method invocation, the primary_expression of the invocation_expression must be a method group. Группа методов определяет один метод для вызова или набор перегруженных методов с возможностью выбора для вызова определенного метода.The method group identifies the one method to invoke or the set of overloaded methods from which to choose a specific method to invoke. В последнем случае определение метода, определенного для вызова строится на основе контекста, предоставленных типов аргументов в argument_list.In the latter case, determination of the specific method to invoke is based on the context provided by the types of the arguments in the argument_list.

Во время привязки обработка вызова метода формы M(A), где M является группой методов (возможно, включающий type_argument_list), и A не является обязательной argument_ список, состоит из следующих действий:The binding-time processing of a method invocation of the form M(A), where M is a method group (possibly including a type_argument_list), and A is an optional argument_list, consists of the following steps:

  • Создается набор методов-кандидатов для вызова метода.The set of candidate methods for the method invocation is constructed. Для каждого метода F связанные с группой метод M:For each method F associated with the method group M:
    • Если F является неуниверсальным F является кандидатом при:If F is non-generic, F is a candidate when:
    • Если F является универсальным и M имеет список аргументов типа не F является кандидатом при:If F is generic and M has no type argument list, F is a candidate when:
      • Определение типа (вывод типа) завершается успешно, предоставляющий список аргументов типа для вызова, иType inference (Type inference) succeeds, inferring a list of type arguments for the call, and
      • После замены аргументов выведенный тип соответствующие параметры типа для метода, все сформированные типы в списке параметров F соответствуют их ограничений (удовлетворяющий ограничениям) и список параметров F применяется по отношению к A (применимого члена функции).Once the inferred type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints (Satisfying constraints), and the parameter list of F is applicable with respect to A (Applicable function member).
    • Если F является универсальным и M включает список аргументов типа F является кандидатом при:If F is generic and M includes a type argument list, F is a candidate when:
      • F имеет тот же номер, тип параметров метода, как указано в списке аргументов типа, иF has the same number of method type parameters as were supplied in the type argument list, and
      • После замены аргументов типа для соответствующих параметров типа метода, все сформированные типы в списке параметров F соответствуют своим ограничениям (удовлетворяющий ограничениям) и список параметров F применяется по отношению к A (применимого члена функции).Once the type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints (Satisfying constraints), and the parameter list of F is applicable with respect to A (Applicable function member).
  • Набор методов-кандидатов уменьшается, чтобы содержать только методы из большинства производных типов: Для каждого метода C.F в наборе, где C — это тип, в которой метод F был объявлен, все методы, объявленные в базовом типе C удаляются из набора.The set of candidate methods is reduced to contain only methods from the most derived types: For each method C.F in the set, where C is the type in which the method F is declared, all methods declared in a base type of C are removed from the set. Кроме того Если C не является типом класса object, все методы, объявленные в типе интерфейса удаляются из набора.Furthermore, if C is a class type other than object, all methods declared in an interface type are removed from the set. (Последнее правило только влияет при группа методов является результатом поиск члена в параметр типа с действительного базового класса, отличного от объекта и эффективный интерфейс непустое значение.)(This latter rule only has affect when the method group was the result of a member lookup on a type parameter having an effective base class other than object and a non-empty effective interface set.)
  • Если результирующий набор методов-кандидатов пуст, оставляются дальнейшей обработки по инструкциям ниже, и вместо этого будет предпринята попытка обработать вызов в виде вызова метода расширения (вызовы методов расширения).If the resulting set of candidate methods is empty, then further processing along the following steps are abandoned, and instead an attempt is made to process the invocation as an extension method invocation (Extension method invocations). Если это не удается, то применимых методов не существует, и возникает ошибка во время привязки.If this fails, then no applicable methods exist, and a binding-time error occurs.
  • Лучше всего подходит набор методов-кандидатов определяется с помощью правил разрешения перегрузки разрешение перегрузки.The best method of the set of candidate methods is identified using the overload resolution rules of Overload resolution. Если подходящий метод не может быть определен, вызов метода является неоднозначным, и возникает ошибка во время привязки.If a single best method cannot be identified, the method invocation is ambiguous, and a binding-time error occurs. При разрешении перегрузки параметров универсального метода, считаются после замены аргументов типа (предоставленных или выведенных) соответствующие параметры типа метода.When performing overload resolution, the parameters of a generic method are considered after substituting the type arguments (supplied or inferred) for the corresponding method type parameters.
  • Последняя проверка выбранного лучшего метода выполняется:Final validation of the chosen best method is performed:
    • Метод проверяется в контексте группы методов: Если лучшим способом является статическим методом, группа методов получилась из simple_name или member_access через тип.The method is validated in the context of the method group: If the best method is a static method, the method group must have resulted from a simple_name or a member_access through a type. Если лучший метод является методом экземпляра, группа методов получилась из simple_name, member_access через переменной или значения, или base_access.If the best method is an instance method, the method group must have resulted from a simple_name, a member_access through a variable or value, or a base_access. Если ни один из этих требований имеет значение true, то возникает ошибка времени привязки.If neither of these requirements is true, a binding-time error occurs.
    • Если лучшим способом является универсальным методом, аргументы типа (предоставленных или выведенных) проходят проверку на соответствие ограничениям (удовлетворяющий ограничениям) объявлены в универсальном методе.If the best method is a generic method, the type arguments (supplied or inferred) are checked against the constraints (Satisfying constraints) declared on the generic method. Если любой аргумент типа не удовлетворяет соответствующим ограничениям для параметра типа, возникает ошибка времени привязки.If any type argument does not satisfy the corresponding constraint(s) on the type parameter, a binding-time error occurs.

После выбора метода и проверены описанные выше действия во время привязки, фактический вызов во время выполнения обрабатывается в соответствии с правилами описано в вызове функции-члена Проверка динамического разрешения перегрузки во время компиляции .Once a method has been selected and validated at binding-time by the above steps, the actual run-time invocation is processed according to the rules of function member invocation described in Compile-time checking of dynamic overload resolution.

Интуитивно понятный правила разрешения, описанные выше действует следующим образом: Чтобы найти конкретный метод, вызванный при вызове метода, начните с тип, указанный в вызове метода и перейти вверх по цепочке наследования, пока не будет найдено объявление по крайней мере один метод применимо, доступный, отличных от переопределения.The intuitive effect of the resolution rules described above is as follows: To locate the particular method invoked by a method invocation, start with the type indicated by the method invocation and proceed up the inheritance chain until at least one applicable, accessible, non-override method declaration is found. Затем выполняется вывод типа и разрешение перегрузки для набора применимо, доступный, отличных от переопределения методов, объявленных в типе и вызвать метод выбранный таким образом.Then perform type inference and overload resolution on the set of applicable, accessible, non-override methods declared in that type and invoke the method thus selected. Если метод не найден, предпринимается попытка обработать вызов в виде вызова метода расширения.If no method was found, try instead to process the invocation as an extension method invocation.

Вызовы методов расширенияExtension method invocations

При вызове метода (вызов в упакованных экземплярах) из одной из формIn a method invocation (Invocations on boxed instances) of one of the forms

expr . identifier ( )

expr . identifier ( args )

expr . identifier < typeargs > ( )

expr . identifier < typeargs > ( args )

При обычной обработке вызова применимые методы не найдены, будет предпринята попытка обработать конструкцию в виде вызова метода расширения.if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. Если expr или любой из args имеет тип времени компиляции dynamic, методы расширения не будут применяться.If expr or any of the args has compile-time type dynamic, extension methods will not apply.

Целью является найти наиболее type_name C, таким образом, соответствующим вызовом статического метода могут иметь место:The objective is to find the best type_name C, so that the corresponding static method invocation can take place:

C . identifier ( expr )

C . identifier ( expr , args )

C . identifier < typeargs > ( expr )

C . identifier < typeargs > ( expr , args )

Метод расширения Ci.Mjправо если:An extension method Ci.Mj is eligible if:

  • Ci представляет собой нестандартную невложенными классCi is a non-generic, non-nested class
  • Имя Mj является идентификаторThe name of Mj is identifier
  • Mj доступен и применим, при применении к аргументам, как статический метод, как показано вышеMj is accessible and applicable when applied to the arguments as a static method as shown above
  • Существует неявное идентификаторов, ссылки или упаковки-преобразования expr в тип первого параметра Mj.An implicit identity, reference or boxing conversion exists from expr to the type of the first parameter of Mj.

Поиск C продолжается следующим образом:The search for C proceeds as follows:

  • Начиная с ближайшим включающего объявление пространства имен, продолжая каждого включающего объявления пространства имен и заканчивая содержащую единицу компиляции, последующие попытки найти набор кандидатов методов расширения:Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to find a candidate set of extension methods:
    • Если заданного пространства имен или блоке компиляции напрямую содержит объявления неуниверсального типа Ci с доступными методами расширения Mj, то набор этих методов является набор кандидатов.If the given namespace or compilation unit directly contains non-generic type declarations Ci with eligible extension methods Mj, then the set of those extension methods is the candidate set.
    • Если типы Ci импортировано using_static_declarations и непосредственно объявлены в пространствах имен, импортированных с using_namespace_directives в заданного пространства имен или блоке компиляции напрямую содержит методы расширения право Mj, то набор этих методов является набор кандидатов.If types Ci imported by using_static_declarations and directly declared in namespaces imported by using_namespace_directives in the given namespace or compilation unit directly contain eligible extension methods Mj, then the set of those extension methods is the candidate set.
  • Если нет набор кандидатов не найден в любой включающего пространства имен объявление или блоке компиляции, возникает ошибка времени компиляции.If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs.
  • В противном случае разрешение перегрузки применяется к набору, как описано в разделе кандидатов (разрешение перегрузки).Otherwise, overload resolution is applied to the candidate set as described in (Overload resolution). Если один лучший метод не найден, возникает ошибка времени компиляции.If no single best method is found, a compile-time error occurs.
  • C — тип, в котором лучший метод объявлен как метод расширения.C is the type within which the best method is declared as an extension method.

С помощью C как целевой объект вызова метода затем обрабатывается как вызов статического метода (Проверка динамического разрешения перегрузки во время компиляции).Using C as a target, the method call is then processed as a static method invocation (Compile-time checking of dynamic overload resolution).

Указанные выше правила означают, что методы экземпляра имеют приоритет по сравнению с методами расширения, что методы расширения, доступные в объявлениях внутреннее пространство имен имеют приоритет над методы расширения, доступные в внешних объявлениях пространств имен и это расширение методы, объявленные непосредственно в пространстве имен имеют приоритет по сравнению с методами расширения, импортируются в этом же пространстве имен с помощью директивы пространства имен.The preceding rules mean that instance methods take precedence over extension methods, that extension methods available in inner namespace declarations take precedence over extension methods available in outer namespace declarations, and that extension methods declared directly in a namespace take precedence over extension methods imported into that same namespace with a using namespace directive. Пример:For example:

public static class E
{
    public static void F(this object obj, int i) { }

    public static void F(this object obj, string s) { }
}

class A { }

class B
{
    public void F(int i) { }
}

class C
{
    public void F(object obj) { }
}

class X
{
    static void Test(A a, B b, C c) {
        a.F(1);              // E.F(object, int)
        a.F("hello");        // E.F(object, string)

        b.F(1);              // B.F(int)
        b.F("hello");        // E.F(object, string)

        c.F(1);              // C.F(object)
        c.F("hello");        // C.F(object)
    }
}

В примере Bметод имеет приоритет над первый метод расширения, и Cметод имеет приоритет над обоими методами расширения.In the example, B's method takes precedence over the first extension method, and C's method takes precedence over both extension methods.

public static class C
{
    public static void F(this int i) { Console.WriteLine("C.F({0})", i); }
    public static void G(this int i) { Console.WriteLine("C.G({0})", i); }
    public static void H(this int i) { Console.WriteLine("C.H({0})", i); }
}

namespace N1
{
    public static class D
    {
        public static void F(this int i) { Console.WriteLine("D.F({0})", i); }
        public static void G(this int i) { Console.WriteLine("D.G({0})", i); }
    }
}

namespace N2
{
    using N1;

    public static class E
    {
        public static void F(this int i) { Console.WriteLine("E.F({0})", i); }
    }

    class Test
    {
        static void Main(string[] args)
        {
            1.F();
            2.G();
            3.H();
        }
    }
}

Выходные данные этого примера является:The output of this example is:

E.F(1)
D.G(2)
C.H(3)

D.G имеет приоритет над C.G, и E.F имеет приоритет над оба D.F и C.F.D.G takes precedence over C.G, and E.F takes precedence over both D.F and C.F.

Вызовы делегатовDelegate invocations

Для вызова делегата primary_expression из invocation_expression должно быть значение delegate_type.For a delegate invocation, the primary_expression of the invocation_expression must be a value of a delegate_type. Кроме того, учитывая delegate_type быть функция-член с такой же список параметров, как delegate_type, delegate_type должно быть применимо () Применимого члена функции) по отношению к argument_list из invocation_expression.Furthermore, considering the delegate_type to be a function member with the same parameter list as the delegate_type, the delegate_type must be applicable (Applicable function member) with respect to the argument_list of the invocation_expression.

Обработка времени выполнения вызова делегата формы D(A), где Dprimary_expression из delegate_type и A является необязательным argument_list, состоит из следующих действий:The run-time processing of a delegate invocation of the form D(A), where D is a primary_expression of a delegate_type and A is an optional argument_list, consists of the following steps:

  • D выполняется оценка.D is evaluated. Если эта оценка вызывает исключение, никакие дополнительные действия выполняются.If this evaluation causes an exception, no further steps are executed.
  • Значение D проверяется, чтобы быть допустимыми.The value of D is checked to be valid. Если значение Dnull, System.NullReferenceException возникает исключение и никакие дополнительные действия не выполняются.If the value of D is null, a System.NullReferenceException is thrown and no further steps are executed.
  • В противном случае D является ссылкой на экземпляр делегата.Otherwise, D is a reference to a delegate instance. Вызовы функций-членов (Проверка динамического разрешения перегрузки во время компиляции) выполняются на каждом из вызываемые объекты в списке вызова делегата.Function member invocations (Compile-time checking of dynamic overload resolution) are performed on each of the callable entities in the invocation list of the delegate. Для вызываемых сущностей, состоящих из экземпляра и метод экземпляра экземпляр для вызова является экземпляром, содержащимся в вызываемая сущность.For callable entities consisting of an instance and instance method, the instance for the invocation is the instance contained in the callable entity.

Доступ к элементамElement access

Element_access состоит из primary_no_array_creation_expression, за которым следует "[" токена, за которым следует argument_list, за которым следует " ]«token.An element_access consists of a primary_no_array_creation_expression, followed by a "[" token, followed by an argument_list, followed by a "]" token. Argument_list состоит из одного или нескольких аргументs, разделенных запятыми.The argument_list consists of one or more arguments, separated by commas.

element_access
    : primary_no_array_creation_expression '[' expression_list ']'
    ;

Argument_list из element_access не может содержать ref или out аргументы.The argument_list of an element_access is not allowed to contain ref or out arguments.

Element_access является динамическим (динамической привязки) Если содержит по крайней мере одно из следующих:An element_access is dynamically bound (Dynamic binding) if at least one of the following holds:

  • Primary_no_array_creation_expression имеет тип времени компиляции dynamic.The primary_no_array_creation_expression has compile-time type dynamic.
  • По крайней мере одно выражение argument_list имеет тип времени компиляции dynamic и primary_no_array_creation_expression не поддерживает тип массива.At least one expression of the argument_list has compile-time type dynamic and the primary_no_array_creation_expression does not have an array type.

В этом случае компилятор классифицирует element_access как значение типа dynamic.In this case the compiler classifies the element_access as a value of type dynamic. Правила для определения значения element_access применяются во время выполнения, используя тип времени выполнения вместо компиляции типа primary_no_array_creation_expressionи argument_list выражения, которые имеют тип времени компиляции dynamic.The rules below to determine the meaning of the element_access are then applied at run-time, using the run-time type instead of the compile-time type of those of the primary_no_array_creation_expression and argument_list expressions which have the compile-time type dynamic. Если primary_no_array_creation_expression не имеет типа во время компиляции dynamic, то доступ к элементам выполнена ограниченная проверка времени компиляции, как описано в разделе проверка динамической компиляции разрешение перегрузки.If the primary_no_array_creation_expression does not have compile-time type dynamic, then the element access undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.

Если primary_no_array_creation_expression из element_access представляет собой значение array_type, element_access — Массив доступа (массива доступа).If the primary_no_array_creation_expression of an element_access is a value of an array_type, the element_access is an array access (Array access). В противном случае primary_no_array_creation_expression должно быть переменной или значения из класса, структуры или тип интерфейса, который содержит один или несколько членов индексатора, в этом случае element_access — доступ к индексатору (доступа к индексатору).Otherwise, the primary_no_array_creation_expression must be a variable or value of a class, struct, or interface type that has one or more indexer members, in which case the element_access is an indexer access (Indexer access).

Доступ к массивуArray access

Для доступа к массиву primary_no_array_creation_expression из element_access должно быть значение array_type.For an array access, the primary_no_array_creation_expression of the element_access must be a value of an array_type. Кроме того argument_list массива не разрешен доступ должен содержать именованные аргументы. Количество выражений в argument_list должен быть таким же, как ранг array_type, и каждое выражение должно иметь тип int, uint, long, ulong, или должен неявно преобразовываться в один или несколько из этих типов.Furthermore, the argument_list of an array access is not allowed to contain named arguments.The number of expressions in the argument_list must be the same as the rank of the array_type, and each expression must be of type int, uint, long, ulong, or must be implicitly convertible to one or more of these types.

Результат вычисления доступа к массиву является переменной типа элемента массива, а именно элемент массива, выбранный по значениям выражений в argument_list.The result of evaluating an array access is a variable of the element type of the array, namely the array element selected by the value(s) of the expression(s) in the argument_list.

Обработка времени выполнения доступа к массиву формы P[A], где Pprimary_no_array_creation_expression из array_type и A является argument_list, состоит из следующих действий:The run-time processing of an array access of the form P[A], where P is a primary_no_array_creation_expression of an array_type and A is an argument_list, consists of the following steps:

  • P выполняется оценка.P is evaluated. Если эта оценка вызывает исключение, никакие дополнительные действия выполняются.If this evaluation causes an exception, no further steps are executed.
  • Выражения индекса argument_list вычисляются в порядке слева направо.The index expressions of the argument_list are evaluated in order, from left to right. После вычисления каждого выражения индекса, неявное преобразование (неявные преобразования) выполняется одно из следующих типов: int, uint, long, ulong.Following evaluation of each index expression, an implicit conversion (Implicit conversions) to one of the following types is performed: int, uint, long, ulong. Будет выбран первый тип, в этом списке, для которого существует неявное преобразование.The first type in this list for which an implicit conversion exists is chosen. Например если выражение индекса имеет тип short затем неявное преобразование в int выполняется, так как неявные преобразования из short для int и из short для long возможны.For instance, if the index expression is of type short then an implicit conversion to int is performed, since implicit conversions from short to int and from short to long are possible. При вычислении выражения индекса или последующих неявное преобразование возникает исключение, оцениваются следующие выражения индекса, и дальнейшие действия не выполняются.If evaluation of an index expression or the subsequent implicit conversion causes an exception, then no further index expressions are evaluated and no further steps are executed.
  • Значение P проверяется, чтобы быть допустимыми.The value of P is checked to be valid. Если значение Pnull, System.NullReferenceException возникает исключение и никакие дополнительные действия не выполняются.If the value of P is null, a System.NullReferenceException is thrown and no further steps are executed.
  • Значение каждого выражения в argument_list проверяются на соответствие фактические границы каждого измерения массива экземпляра массива, P.The value of each expression in the argument_list is checked against the actual bounds of each dimension of the array instance referenced by P. Если одно или несколько значений выходят за пределы диапазона, System.IndexOutOfRangeException возникает исключение и никакие дополнительные действия не выполняются.If one or more values are out of range, a System.IndexOutOfRangeException is thrown and no further steps are executed.
  • Расположение элемента массива, заданного выражениями индекса является вычисляемым, и оно становится результатом доступ к массиву.The location of the array element given by the index expression(s) is computed, and this location becomes the result of the array access.

Доступ к индексаторуIndexer access

Для доступа к индексатору primary_no_array_creation_expression из element_access должно быть переменной или значения из класса, структуры или тип интерфейса, и этот тип должен реализовывать один или несколько индексаторы, которые можно использовать по отношению к argument_list из element_access.For an indexer access, the primary_no_array_creation_expression of the element_access must be a variable or value of a class, struct, or interface type, and this type must implement one or more indexers that are applicable with respect to the argument_list of the element_access.

Обработка времени привязки доступа к индексатору формы P[A], где Pprimary_no_array_creation_expression класса, структуры или тип интерфейса T, и Aargument_list, состоит из следующих действий:The binding-time processing of an indexer access of the form P[A], where P is a primary_no_array_creation_expression of a class, struct, or interface type T, and A is an argument_list, consists of the following steps:

  • Набор индексаторов, предоставляемых T создается.The set of indexers provided by T is constructed. Набор состоит из всех индексаторов, объявленных в T или базовый тип T , которые не являются override объявления и доступны в текущем контексте (доступ к членам).The set consists of all indexers declared in T or a base type of T that are not override declarations and are accessible in the current context (Member access).
  • Набор уменьшается до индексаторов, которые применимы и не скрыты другими индексаторами.The set is reduced to those indexers that are applicable and not hidden by other indexers. Следующие правила применяются для каждого индексатора S.I в наборе, где S — это тип, в которой индексатор I объявляется:The following rules are applied to each indexer S.I in the set, where S is the type in which the indexer I is declared:
    • Если I не применяется по отношению к A (применимого члена функции), затем I удаляется из набора.If I is not applicable with respect to A (Applicable function member), then I is removed from the set.
    • Если I применяется по отношению к A (применимого члена функции), затем всех индексаторов, объявленных в базовом типе S удаляются из набора.If I is applicable with respect to A (Applicable function member), then all indexers declared in a base type of S are removed from the set.
    • Если I применяется по отношению к A (применимого члена функции) и S не является типом класса object, всех индексаторов, объявленных в интерфейсе, удаляются из набора.If I is applicable with respect to A (Applicable function member) and S is a class type other than object, all indexers declared in an interface are removed from the set.
  • Если результирующий набор индексаторов-кандидатов пуст, то существовать нет применимых индексаторов, и возникает ошибка во время привязки.If the resulting set of candidate indexers is empty, then no applicable indexers exist, and a binding-time error occurs.
  • Лучший индексатор из набора индексаторов-кандидатов определяется с помощью правил разрешения перегрузки разрешение перегрузки.The best indexer of the set of candidate indexers is identified using the overload resolution rules of Overload resolution. Если не удается определить лучший один индексатор, доступа к индексатору является неоднозначным, и возникает ошибка во время привязки.If a single best indexer cannot be identified, the indexer access is ambiguous, and a binding-time error occurs.
  • Выражения индекса argument_list вычисляются в порядке слева направо.The index expressions of the argument_list are evaluated in order, from left to right. Результат обработки доступа к индексатору — это выражение, которые классифицируются как доступ к индексатору.The result of processing the indexer access is an expression classified as an indexer access. Выражения доступа к индексатору ссылается на индексатор, определенный на предыдущем шаге и имеет связанное выражение экземпляра из P и связанный список аргументов из A.The indexer access expression references the indexer determined in the step above, and has an associated instance expression of P and an associated argument list of A.

В зависимости от контекста, в котором оно использовано, доступ к индексатору приводит вызов либо метод доступа get или метода доступа set индексатора.Depending on the context in which it is used, an indexer access causes invocation of either the get accessor or the set accessor of the indexer. Если доступ к индексатору является целевым объектом назначения, метода доступа set вызывается для присвоения нового значения (простое присваивание).If the indexer access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). Во всех остальных случаях метод доступа get вызывается для получения текущего значения (значения выражений).In all other cases, the get accessor is invoked to obtain the current value (Values of expressions).

Такой доступThis access

Объект this_access состоит из ключевого слова this.A this_access consists of the reserved word this.

this_access
    : 'this'
    ;

Объект this_access допускается только в блок конструктор экземпляра, методе экземпляра или метода доступа к экземпляру.A this_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Он имеет одно из следующих значений:It has one of the following meanings:

  • Когда this используется в primary_expression внутри конструктора экземпляра класса, он классифицируется как значение.When this is used in a primary_expression within an instance constructor of a class, it is classified as a value. Тип значения имеет тип экземпляра (тип экземпляра) класса, в котором происходит это использование, и значение является ссылкой на создаваемый объект.The type of the value is the instance type (The instance type) of the class within which the usage occurs, and the value is a reference to the object being constructed.
  • Когда this используется в primary_expression внутри метода экземпляра или методе доступа экземпляра класса, он классифицируется как значение.When this is used in a primary_expression within an instance method or instance accessor of a class, it is classified as a value. Тип значения имеет тип экземпляра (тип экземпляра) класса, в котором происходит это использование, и значение является ссылкой на объект, для которого был вызван метод или метод доступа.The type of the value is the instance type (The instance type) of the class within which the usage occurs, and the value is a reference to the object for which the method or accessor was invoked.
  • Когда this используется в primary_expression внутри конструктора экземпляра структуры, он классифицируется как переменная.When this is used in a primary_expression within an instance constructor of a struct, it is classified as a variable. Тип переменной является тип экземпляра (тип экземпляра) в течение которого происходит это использование, а переменная представляет структуры структуры.The type of the variable is the instance type (The instance type) of the struct within which the usage occurs, and the variable represents the struct being constructed. this Переменной конструктора экземпляра структуры ведет себя так же, как out параметр типа структуры — в частности, это означает, что переменной должен быть явно присвоен в каждом пути исполнения экземпляра конструктор.The this variable of an instance constructor of a struct behaves exactly the same as an out parameter of the struct type—in particular, this means that the variable must be definitely assigned in every execution path of the instance constructor.
  • Когда this используется в primary_expression внутри метода экземпляра или методе доступа экземпляра структуры, он классифицируется как переменная.When this is used in a primary_expression within an instance method or instance accessor of a struct, it is classified as a variable. Тип переменной является тип экземпляра (тип экземпляра) структуры, в котором осуществляется использование.The type of the variable is the instance type (The instance type) of the struct within which the usage occurs.
    • Если метод или метод доступа не является итератором (итераторы), this переменная представляет структуру, для которого был вызван метод или метод доступа и ведет себя так же, как ref параметр типа структуры.If the method or accessor is not an iterator (Iterators), the this variable represents the struct for which the method or accessor was invoked, and behaves exactly the same as a ref parameter of the struct type.
    • Если метод или метод доступа является итератором, this переменная представляет копию структуры, для которого был вызван метод или метод доступа и ведет себя так же, как значение параметра типа структуры.If the method or accessor is an iterator, the this variable represents a copy of the struct for which the method or accessor was invoked, and behaves exactly the same as a value parameter of the struct type.

Использование this в primary_expression в контексте, отличном от приведенных выше является ошибкой во время компиляции.Use of this in a primary_expression in a context other than the ones listed above is a compile-time error. В частности, это не можно будет ссылаться в this в статический метод, метод доступа статического свойства, или в variable_initializer объявления поля.In particular, it is not possible to refer to this in a static method, a static property accessor, or in a variable_initializer of a field declaration.

Доступ к базовым членамBase access

Объект base_access состоит из ключевого слова base следуют либо "." токена и идентификатор или значение argument_list заключенная в квадратные скобки:A base_access consists of the reserved word base followed by either a "." token and an identifier or an argument_list enclosed in square brackets:

base_access
    : 'base' '.' identifier
    | 'base' '[' expression_list ']'
    ;

Объект base_access используется для доступа к членам базового класса, которые скрыты с такими же именами в текущем классе или структуре.A base_access is used to access base class members that are hidden by similarly named members in the current class or struct. Объект base_access допускается только в блок конструктор экземпляра, методе экземпляра или метода доступа к экземпляру.A base_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Когда base.I происходит в классе или структуре, I должно обозначать член базового класса этого класса или структуры.When base.I occurs in a class or struct, I must denote a member of the base class of that class or struct. Аналогичным образом, если base[E] происходит в классе, применимый индексатор должен существовать в базовом классе.Likewise, when base[E] occurs in a class, an applicable indexer must exist in the base class.

Во время привязки base_access выражения формы base.I и base[E] вычисляются точно так же, как если бы они были написаны ((B)this).I и ((B)this)[E], где B является базовым классом класса или структуры, в котором находится эта конструкция.At binding-time, base_access expressions of the form base.I and base[E] are evaluated exactly as if they were written ((B)this).I and ((B)this)[E], where B is the base class of the class or struct in which the construct occurs. Таким образом base.I и base[E] соответствуют this.I и this[E], за исключением this рассматривается как экземпляр базового класса.Thus, base.I and base[E] correspond to this.I and this[E], except this is viewed as an instance of the base class.

Когда base_access ссылается на элемент виртуальной функции (метода, свойства или индексатора), определение которого функции-члена для вызова во время выполнения (Проверка динамического разрешения перегрузки во время компиляции ) изменяется.When a base_access references a virtual function member (a method, property, or indexer), the determination of which function member to invoke at run-time (Compile-time checking of dynamic overload resolution) is changed. Функцию-член, вызываемая определяется путем нахождения наиболее производной реализацией (виртуальных методов) члена функции по отношению к B (а не по отношению к тип времени выполнения this, как бы обычным в системе счисления с основанием доступ).The function member that is invoked is determined by finding the most derived implementation (Virtual methods) of the function member with respect to B (instead of with respect to the run-time type of this, as would be usual in a non-base access). Таким образом, в пределах override из virtual функции-члена base_access может использоваться для вызова унаследованной реализации функции-члена.Thus, within an override of a virtual function member, a base_access can be used to invoke the inherited implementation of the function member. Если функция-член, на который ссылается base_access является абстрактным, возникает ошибка во время привязки.If the function member referenced by a base_access is abstract, a binding-time error occurs.

Постфиксные операторы инкремента и декрементаPostfix increment and decrement operators

post_increment_expression
    : primary_expression '++'
    ;

post_decrement_expression
    : primary_expression '--'
    ;

Операнд постфиксного инкремента или декремента должен быть выражением, классифицируется как переменная, доступ к свойству или индексатору.The operand of a postfix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. Результат операции является значение совпадает с типом операнда.The result of the operation is a value of the same type as the operand.

Если primary_expression имеет тип времени компиляции dynamic , а затем оператор является динамическим (динамической привязки), post_increment_expressionили post_decrement_expression имеет тип времени компиляции dynamic и следующие правила применяются во время выполнения, используя тип среды выполнения primary_expression.If the primary_expression has the compile-time type dynamic then the operator is dynamically bound (Dynamic binding), the post_increment_expression or post_decrement_expression has the compile-time type dynamic and the following rules are applied at run-time using the run-time type of the primary_expression.

Если увеличить Операнд постфиксного оператора декремента является свойство или индексатор, свойство или индексатор должны иметь get и set метода доступа.If the operand of a postfix increment or decrement operation is a property or indexer access, the property or indexer must have both a get and a set accessor. Если это не так, возникает ошибка времени привязки.If this is not the case, a binding-time error occurs.

Разрешение перегрузки унарного оператора (разрешение перегрузки унарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Предопределенные ++ и -- операторов существуют для следующих типов: sbyte, byte, short, ushort, int, uint, long, ulong, char , float, double, decimalи любой тип перечисления.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Предопределенный ++ операторы возвращают значение, полученное путем прибавления единицы к операнд и предварительно определенных -- операторы возвращают значение, полученное путем вычитания 1 из операнда.The predefined ++ operators return the value produced by adding 1 to the operand, and the predefined -- operators return the value produced by subtracting 1 from the operand. В checked контекста, если результат сложения или вычитания находится вне диапазона типа результата, а тип результата — целый тип или тип перечисления, System.OverflowException возникает исключение.In a checked context, if the result of this addition or subtraction is outside the range of the result type and the result type is an integral type or enum type, a System.OverflowException is thrown.

Во время выполнения обработки Постфиксный инкремент или операция формы декремента x++ или x-- состоит из следующих действий:The run-time processing of a postfix increment or decrement operation of the form x++ or x-- consists of the following steps:

  • Если x классифицируется как переменная:If x is classified as a variable:
    • x вычисляется для создания переменной.x is evaluated to produce the variable.
    • Значение x сохраняется.The value of x is saved.
    • Выбранный оператор вызывается с сохраненным значением x аргументом.The selected operator is invoked with the saved value of x as its argument.
    • Значение, возвращаемое оператором хранится в расположении, указанном при вычислении x.The value returned by the operator is stored in the location given by the evaluation of x.
    • Сохраненное значение x становится результатом операции.The saved value of x becomes the result of the operation.
  • Если x классифицируется как свойство или индексатор доступа:If x is classified as a property or indexer access:
    • Выражение экземпляра (если x не static) и список аргументов (если x имеет доступ к индексатору) связан x оцениваются, и полученные результаты используются в последующих get и set вызовы метода доступа.The instance expression (if x is not static) and the argument list (if x is an indexer access) associated with x are evaluated, and the results are used in the subsequent get and set accessor invocations.
    • get Метод доступа x вызывается и возвращаемое значение сохраняется.The get accessor of x is invoked and the returned value is saved.
    • Выбранный оператор вызывается с сохраненным значением x аргументом.The selected operator is invoked with the saved value of x as its argument.
    • set Метод доступа x вызывается со значением, возвращенным оператором в качестве его value аргумент.The set accessor of x is invoked with the value returned by the operator as its value argument.
    • Сохраненное значение x становится результатом операции.The saved value of x becomes the result of the operation.

++ И -- операторы также поддерживают префикса (префиксный инкремент и декремент операторы).The ++ and -- operators also support prefix notation (Prefix increment and decrement operators). Как правило, результат x++ или x-- является значением x до операции, тогда как результат ++x или --x является значением x после завершения операции.Typically, the result of x++ or x-- is the value of x before the operation, whereas the result of ++x or --x is the value of x after the operation. В любом случае x сам имеет то же значение после выполнения операции.In either case, x itself has the same value after the operation.

operator ++ Или operator -- реализации можно вызывать в префиксной и постфиксной форме.An operator ++ or operator -- implementation can be invoked using either postfix or prefix notation. Это не могут существовать разные реализации операторов для обозначения.It is not possible to have separate operator implementations for the two notations.

Оператор newThe new operator

new Оператор используется для создания новых экземпляров типов.The new operator is used to create new instances of types.

Существует три формы new выражения:There are three forms of new expressions:

  • Выражения создания объектов используются для создания новых экземпляров типов классов и типов значений.Object creation expressions are used to create new instances of class types and value types.
  • Выражения создания массива используются для создания новых экземпляров типов массивов.Array creation expressions are used to create new instances of array types.
  • Выражения создания делегата используются для создания новых экземпляров делегатов типов.Delegate creation expressions are used to create new instances of delegate types.

new Оператор подразумевает создание экземпляра типа, но не подразумевает динамическое выделение памяти.The new operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. В частности, экземпляры типов значений не требуют дополнительной памяти за пределами переменных, в которых они находятся, и динамическое распределение не происходит при new используется для создания экземпляров типов значений.In particular, instances of value types require no additional memory beyond the variables in which they reside, and no dynamic allocations occur when new is used to create instances of value types.

Выражения создания объектовObject creation expressions

Object_creation_expression используется для создания нового экземпляра class_type или value_type.An object_creation_expression is used to create a new instance of a class_type or a value_type.

object_creation_expression
    : 'new' type '(' argument_list? ')' object_or_collection_initializer?
    | 'new' type object_or_collection_initializer
    ;

object_or_collection_initializer
    : object_initializer
    | collection_initializer
    ;

Тип из object_creation_expression должно быть class_type, value_type или параметр_типа .The type of an object_creation_expression must be a class_type, a value_type or a type_parameter. Тип не может быть abstract class_type.The type cannot be an abstract class_type.

Необязательный argument_list (списки аргументов) разрешается, только в том случае, если типclass_type или struct_ Тип.The optional argument_list (Argument lists) is permitted only if the type is a class_type or a struct_type.

Выражения создания объекта можно опустить список аргументов конструктора и скобок при условии, что он включает в себя инициализатор объекта или коллекции.An object creation expression can omit the constructor argument list and enclosing parentheses provided it includes an object initializer or collection initializer. Пропуск список аргументов конструктора и скобок — эквивалентен предложению пустым списком аргументов.Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.

Обработка выражения создания объекта, который включает в себя инициализатор объекта или коллекции включает сначала выполняется конструктор экземпляра, а затем обрабатывая инициализация члена или элемента, указанного в инициализаторе объекта ( Инициализаторы объектов) или коллекции (инициализаторы).Processing of an object creation expression that includes an object initializer or collection initializer consists of first processing the instance constructor and then processing the member or element initializations specified by the object initializer (Object initializers) or collection initializer (Collection initializers).

Если любой из аргументов в необязательном argument_list имеет тип времени компиляции dynamic то object_creation_expression является динамическим (динамической привязки) следующие правила применяются во время выполнения с использованием типа во время выполнения эти аргументы argument_list , имеющих тип времени компиляции dynamic.If any of the arguments in the optional argument_list has the compile-time type dynamic then the object_creation_expression is dynamically bound (Dynamic binding) and the following rules are applied at run-time using the run-time type of those arguments of the argument_list that have the compile time type dynamic. Тем не менее, для создания объекта выполняется ограниченная проверка времени компиляции, как описано в разделе Проверка динамического разрешения перегрузки во время компиляции.However, the object creation undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.

Во время привязки обработка object_creation_expression формы new T(A), где Tclass_type или value_type и A не является обязательной argument_list, состоит из следующих действий:The binding-time processing of an object_creation_expression of the form new T(A), where T is a class_type or a value_type and A is an optional argument_list, consists of the following steps:

  • Если Tvalue_type и A отсутствует:If T is a value_type and A is not present:
    • Object_creation_expression является вызов конструктора по умолчанию.The object_creation_expression is a default constructor invocation. Результат object_creation_expression является значением типа T, то есть значение по умолчанию для T как определено в типа System.ValueType.The result of the object_creation_expression is a value of type T, namely the default value for T as defined in The System.ValueType type.
  • В противном случае, если Tпараметр_типа и A отсутствует:Otherwise, if T is a type_parameter and A is not present:
    • Если нет ограничение типа значения или ограничение конструктора (ограничения параметров типа) был указан для T, возникает ошибка во время привязки.If no value type constraint or constructor constraint (Type parameter constraints) has been specified for T, a binding-time error occurs.
    • Результат object_creation_expression является значение типа времени выполнения, привязанного параметра типа, а именно результат вызова конструктора по умолчанию этого типа.The result of the object_creation_expression is a value of the run-time type that the type parameter has been bound to, namely the result of invoking the default constructor of that type. Тип времени выполнения может быть ссылочным типом или типом значения.The run-time type may be a reference type or a value type.
  • В противном случае, если Tclass_type или struct_type:Otherwise, if T is a class_type or a struct_type:
    • Если Tabstract class_type, возникает ошибка времени компиляции.If T is an abstract class_type, a compile-time error occurs.
    • Вызываемый конструктор экземпляра определяется с помощью правил разрешения перегрузки разрешение перегрузки.The instance constructor to invoke is determined using the overload resolution rules of Overload resolution. Набор кандидатов конструкторов экземпляров состоит из всех доступный экземпляр конструкторов, объявленных в T по отношению к которому применимы A (применимого члена функции).The set of candidate instance constructors consists of all accessible instance constructors declared in T which are applicable with respect to A (Applicable function member). Если набор кандидатов конструкторов экземпляров пуст или не может быть определен один лучший конструктор экземпляра, возникает ошибка времени привязки.If the set of candidate instance constructors is empty, or if a single best instance constructor cannot be identified, a binding-time error occurs.
    • Результат object_creation_expression является значением типа T, а именно: значение, создаваемое путем вызова конструктора экземпляра, определенного в предыдущем шаге.The result of the object_creation_expression is a value of type T, namely the value produced by invoking the instance constructor determined in the step above.
  • В противном случае object_creation_expression является недопустимым, и возникает ошибка во время привязки.Otherwise, the object_creation_expression is invalid, and a binding-time error occurs.

Даже если object_creation_expression динамически привязаны, во время компиляции тип — по-прежнему T.Even if the object_creation_expression is dynamically bound, the compile-time type is still T.

Во время выполнения обработки object_creation_expression формы new T(A), где Tclass_type или struct_type и A не является обязательной argument_list, состоит из следующих действий:The run-time processing of an object_creation_expression of the form new T(A), where T is class_type or a struct_type and A is an optional argument_list, consists of the following steps:

  • Если Tclass_type:If T is a class_type:
    • Новый экземпляр класса T выделяется.A new instance of class T is allocated. Если не хватает памяти для выделения нового экземпляра, System.OutOfMemoryException возникает исключение и никакие дополнительные действия не выполняются.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • Все поля нового экземпляра инициализируются со значениями по умолчанию (значения по умолчанию).All fields of the new instance are initialized to their default values (Default values).
    • Конструктор экземпляра вызывается в соответствии с правилами вызова функции-члена (Проверка динамического разрешения перегрузки во время компиляции).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Ссылку на созданный экземпляр автоматически передается конструктору экземпляра и экземпляр может осуществляться из этого конструктора с this.A reference to the newly allocated instance is automatically passed to the instance constructor and the instance can be accessed from within that constructor as this.
  • Если Tstruct_type:If T is a struct_type:
    • Экземпляр типа T создается путем выделения временной локальной переменной.An instance of type T is created by allocating a temporary local variable. Так как конструктор экземпляра struct_type для явного присвоения значений для каждого поля экземпляра, необходима инициализация временной переменной не требуется.Since an instance constructor of a struct_type is required to definitely assign a value to each field of the instance being created, no initialization of the temporary variable is necessary.
    • Конструктор экземпляра вызывается в соответствии с правилами вызова функции-члена (Проверка динамического разрешения перегрузки во время компиляции).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Ссылку на созданный экземпляр автоматически передается конструктору экземпляра и экземпляр может осуществляться из этого конструктора с this.A reference to the newly allocated instance is automatically passed to the instance constructor and the instance can be accessed from within that constructor as this.

Инициализаторы объектовObject initializers

Инициализатора объекта указывает значения для ноль или более полей, свойств или индексированными элементами объекта.An object initializer specifies values for zero or more fields, properties or indexed elements of an object.

object_initializer
    : '{' member_initializer_list? '}'
    | '{' member_initializer_list ',' '}'
    ;

member_initializer_list
    : member_initializer (',' member_initializer)*
    ;

member_initializer
    : initializer_target '=' initializer_value
    ;

initializer_target
    : identifier
    | '[' argument_list ']'
    ;

initializer_value
    : expression
    | object_or_collection_initializer
    ;

Инициализатор объекта состоит из последовательности инициализаторов членов, заключенных { и } маркеров и разделены запятыми.An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas. Каждый member_initializer определяет целевой объект для инициализации.Each member_initializer designates a target for the initialization. Идентификатор необходимо присвоить имя к доступному полю или свойству объекта выполняется инициализация, тогда как argument_list заключены в квадратные скобки необходимо указать аргументы для индексатора доступны на инициализируемый объект.An identifier must name an accessible field or property of the object being initialized, whereas an argument_list enclosed in square brackets must specify arguments for an accessible indexer on the object being initialized. Это ошибка для инициализатора объекта для включения более чем один инициализатор элементов по одному полю или свойству.It is an error for an object initializer to include more than one member initializer for the same field or property.

Каждый initializer_target следуют знак равенства и выражение, инициализатора объекта или инициализатор коллекции.Each initializer_target is followed by an equals sign and either an expression, an object initializer or a collection initializer. Не поддерживается для выражений внутри инициализатора объекта для ссылки на только что созданный объект, который он инициализируется.It is not possible for expressions within the object initializer to refer to the newly created object it is initializing.

Инициализатор члена, который указывает выражение после знака равенства обрабатывается так же, как и присваивание (простое присваивание) к целевому объекту.A member initializer that specifies an expression after the equals sign is processed in the same way as an assignment (Simple assignment) to the target.

Инициализатор члена, который указывает инициализатора объекта, после знака равенства инициализатора вложенного объекта, т. е. инициализация внедренный объект.A member initializer that specifies an object initializer after the equals sign is a nested object initializer, i.e. an initialization of an embedded object. Вместо присвоения нового значения для поля или свойства, назначения в инициализаторе вложенного объекта, рассматриваются как назначения для элементов поля или свойства.Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. Инициализаторы вложенных объектов не может применяться к свойствам с типом значения или только для чтения полям с типом значения.Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.

Инициализатор члена, который определяет инициализатор коллекции после знака равенства, выполняет инициализацию внедренной коллекции.A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Вместо назначения новой коллекции для целевого поля, свойства или индексатора, элементы, указанные в инициализаторе добавляются в коллекцию, ссылается на целевой объект.Instead of assigning a new collection to the target field, property or indexer, the elements given in the initializer are added to the collection referenced by the target. Целевой объект должен иметь тип коллекции, который удовлетворяет требованиям, указанным в Инициализаторы коллекций.The target must be of a collection type that satisfies the requirements specified in Collection initializers.

Аргументы для инициализатора индекса всегда вычисляется только один раз.The arguments to an index initializer will always be evaluated exactly once. Таким образом даже если аргументы в итоге никогда не используется начало (например, из-за пустого инициализатора вложенной), они будут вычисляться для побочного эффекта.Thus, even if the arguments end up never getting used (e.g. because of an empty nested initializer), they will be evaluated for their side effects.

Следующий класс представляет точку с помощью двух координат:The following class represents a point with two coordinates:

public class Point
{
    int x, y;

    public int X { get { return x; } set { x = value; } }
    public int Y { get { return y; } set { y = value; } }
}

Экземпляр Point можно создавать и инициализировать следующим образом:An instance of Point can be created and initialized as follows:

Point a = new Point { X = 0, Y = 1 };

который имеет тот же эффект, чтоwhich has the same effect as

Point __a = new Point();
__a.X = 0;
__a.Y = 1; 
Point a = __a;

где __a является невидимой и недоступной временной переменной.where __a is an otherwise invisible and inaccessible temporary variable. Следующий класс представляет собой прямоугольник, созданный из двух точек:The following class represents a rectangle created from two points:

public class Rectangle
{
    Point p1, p2;

    public Point P1 { get { return p1; } set { p1 = value; } }
    public Point P2 { get { return p2; } set { p2 = value; } }
}

Экземпляр Rectangle можно создавать и инициализировать следующим образом:An instance of Rectangle can be created and initialized as follows:

Rectangle r = new Rectangle {
    P1 = new Point { X = 0, Y = 1 },
    P2 = new Point { X = 2, Y = 3 }
};

который имеет тот же эффект, чтоwhich has the same effect as

Rectangle __r = new Rectangle();
Point __p1 = new Point();
__p1.X = 0;
__p1.Y = 1;
__r.P1 = __p1;
Point __p2 = new Point();
__p2.X = 2;
__p2.Y = 3;
__r.P2 = __p2; 
Rectangle r = __r;

где __r, __p1 и __p2 являются временные переменные, которые в противном случае и недоступными.where __r, __p1 and __p2 are temporary variables that are otherwise invisible and inaccessible.

Если Rectangleв конструктор выделяет два внедренных Point экземпляровIf Rectangle's constructor allocates the two embedded Point instances

public class Rectangle
{
    Point p1 = new Point();
    Point p2 = new Point();

    public Point P1 { get { return p1; } }
    public Point P2 { get { return p2; } }
}

Следующая конструкция может использоваться для инициализации внедренный Point экземпляров, вместо назначения новых экземпляров:the following construct can be used to initialize the embedded Point instances instead of assigning new instances:

Rectangle r = new Rectangle {
    P1 = { X = 0, Y = 1 },
    P2 = { X = 2, Y = 3 }
};

который имеет тот же эффект, чтоwhich has the same effect as

Rectangle __r = new Rectangle();
__r.P1.X = 0;
__r.P1.Y = 1;
__r.P2.X = 2;
__r.P2.Y = 3;
Rectangle r = __r;

Если определение соответствующего языка c, в следующем примере:Given an appropriate definition of C, the following example:

var c = new C {
    x = true,
    y = { a = "Hello" },
    z = { 1, 2, 3 },
    ["x"] = 5,
    [0,0] = { "a", "b" },
    [1,2] = {}
};

эквивалентно эту серию назначения:is equivalent to this series of assignments:

C __c = new C();
__c.x = true;
__c.y.a = "Hello";
__c.z.Add(1); 
__c.z.Add(2);
__c.z.Add(3);
string __i1 = "x";
__c[__i1] = 5;
int __i2 = 0, __i3 = 0;
__c[__i2,__i3].Add("a");
__c[__i2,__i3].Add("b");
int __i4 = 1, __i5 = 2;
var c = __c;

где __cи пр., созданные переменные, которые являются и недоступными к исходному коду.where __c, etc., are generated variables that are invisible and inaccessible to the source code. Обратите внимание, что аргументы для [0,0] вычисляется только один раз и аргументы для [1,2] вычисляются один раз несмотря на то, что они никогда не используются.Note that the arguments for [0,0] are evaluated only once, and the arguments for [1,2] are evaluated once even though they are never used.

Инициализаторы коллекцийCollection initializers

Инициализатор коллекции определяет элементы в коллекцию.A collection initializer specifies the elements of a collection.

collection_initializer
    : '{' element_initializer_list '}'
    | '{' element_initializer_list ',' '}'
    ;

element_initializer_list
    : element_initializer (',' element_initializer)*
    ;

element_initializer
    : non_assignment_expression
    | '{' expression_list '}'
    ;

expression_list
    : expression (',' expression)*
    ;

Инициализатор коллекции состоит из последовательности инициализаторов элементов, заключенных { и } маркеров и разделены запятыми.A collection initializer consists of a sequence of element initializers, enclosed by { and } tokens and separated by commas. Каждый инициализатор элемента задает элемент для добавления инициализируемый объект коллекции и состоит из списка выражений, заключенных { и } маркеров и разделены запятыми.Each element initializer specifies an element to be added to the collection object being initialized, and consists of a list of expressions enclosed by { and } tokens and separated by commas. Инициализатор элемента с одним выражением можно записать и без фигурных скобок, но не может быть выражением присваивания, чтобы избежать неоднозначности с инициализаторы членов.A single-expression element initializer can be written without braces, but cannot then be an assignment expression, to avoid ambiguity with member initializers. Non_assignment_expression рабочей определяется в выражение.The non_assignment_expression production is defined in Expression.

Ниже приведен пример выражения создания объекта, который включает в себя инициализатор коллекции:The following is an example of an object creation expression that includes a collection initializer:

List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

Объект коллекции, к которому применяется инициализатор коллекции должны иметь тип, реализующий System.Collections.IEnumerable или возникает ошибка времени компиляции.The collection object to which a collection initializer is applied must be of a type that implements System.Collections.IEnumerable or a compile-time error occurs. Для каждого выбранного элемента в порядке, инициализатор вызывает Add метод для целевого объекта со списком выражения инициализатора элементов как список аргументов, применение поиске обычного элемента и разрешение для каждого вызова перегрузки.For each specified element in order, the collection initializer invokes an Add method on the target object with the expression list of the element initializer as argument list, applying normal member lookup and overload resolution for each invocation. Таким образом, объект коллекции должен иметь соответствующий экземпляр или расширение метод с именем Add для каждого элемента инициализатора.Thus, the collection object must have an applicable instance or extension method with the name Add for each element initializer.

Следующий класс представляет контакт с именем и список номеров телефонов:The following class represents a contact with a name and a list of phone numbers:

public class Contact
{
    string name;
    List<string> phoneNumbers = new List<string>();

    public string Name { get { return name; } set { name = value; } }

    public List<string> PhoneNumbers { get { return phoneNumbers; } }
}

Объект List<Contact> можно создавать и инициализировать следующим образом:A List<Contact> can be created and initialized as follows:

var contacts = new List<Contact> {
    new Contact {
        Name = "Chris Smith",
        PhoneNumbers = { "206-555-0101", "425-882-8080" }
    },
    new Contact {
        Name = "Bob Harris",
        PhoneNumbers = { "650-555-0199" }
    }
};

который имеет тот же эффект, чтоwhich has the same effect as

var __clist = new List<Contact>();
Contact __c1 = new Contact();
__c1.Name = "Chris Smith";
__c1.PhoneNumbers.Add("206-555-0101");
__c1.PhoneNumbers.Add("425-882-8080");
__clist.Add(__c1);
Contact __c2 = new Contact();
__c2.Name = "Bob Harris";
__c2.PhoneNumbers.Add("650-555-0199");
__clist.Add(__c2);
var contacts = __clist;

где __clist, __c1 и __c2 являются временные переменные, которые в противном случае и недоступными.where __clist, __c1 and __c2 are temporary variables that are otherwise invisible and inaccessible.

Выражения создания массиваArray creation expressions

Array_creation_expression используется для создания нового экземпляра array_type.An array_creation_expression is used to create a new instance of an array_type.

array_creation_expression
    : 'new' non_array_type '[' expression_list ']' rank_specifier* array_initializer?
    | 'new' array_type array_initializer
    | 'new' rank_specifier array_initializer
    ;

Выражение создания массива из первой формы выделяет экземпляр массива тип, полученный в результате удаления всех отдельных выражений из списка выражений.An array creation expression of the first form allocates an array instance of the type that results from deleting each of the individual expressions from the expression list. Например, выражение создания массива new int[10,20] создает экземпляр массива типа int[,]и выражение создания массива new int[10][,] создает массив объектов типа int[][,].For example, the array creation expression new int[10,20] produces an array instance of type int[,], and the array creation expression new int[10][,] produces an array of type int[][,]. Каждое выражение в списке выражений должен иметь тип int, uint, long, или ulong, или неявно преобразуется в один или несколько из этих типов.Each expression in the expression list must be of type int, uint, long, or ulong, or implicitly convertible to one or more of these types. Значение каждого выражения определяет длину соответствующего измерения в экземпляре во вновь выделенный массива.The value of each expression determines the length of the corresponding dimension in the newly allocated array instance. Так как длина размерности массива должны быть неотрицательными, является ошибкой во время компиляции для constant_expression с отрицательными значениями в списке выражений.Since the length of an array dimension must be nonnegative, it is a compile-time error to have a constant_expression with a negative value in the expression list.

Только в небезопасном контексте (небезопасных контекстах), макет массивов не определен.Except in an unsafe context (Unsafe contexts), the layout of arrays is unspecified.

Если выражение создания массива первого типа включает в себя инициализатор массива, каждое выражение в списке выражений должно быть константой, и ранга и размерности длины, указанные в списке выражений должны совпадать с инициализатором массива.If an array creation expression of the first form includes an array initializer, each expression in the expression list must be a constant and the rank and dimension lengths specified by the expression list must match those of the array initializer.

В выражение создания массива в форме во втором и третьем ранг спецификатора типа "или" ранг заданного массива должна соответствовать инициализатора массива.In an array creation expression of the second or third form, the rank of the specified array type or rank specifier must match that of the array initializer. Длины отдельных измерений выводятся из числа элементов в каждом из соответствующих уровней вложения инициализатора массива.The individual dimension lengths are inferred from the number of elements in each of the corresponding nesting levels of the array initializer. Таким образом выражениеThus, the expression

new int[,] {{0, 1}, {2, 3}, {4, 5}}

в точности соответствуетexactly corresponds to

new int[3, 2] {{0, 1}, {2, 3}, {4, 5}}

Выражение создания массива третьего типа называется неявно типизированные выражение создания массива.An array creation expression of the third form is referred to as an implicitly typed array creation expression. Это похоже на второй форме, за исключением того, что тип элемента массива не указан явно, но определяется как наиболее общий тип (поиск это наиболее распространенный тип набора выражений) из набора выражений в массиве инициализатор.It is similar to the second form, except that the element type of the array is not explicitly given, but determined as the best common type (Finding the best common type of a set of expressions) of the set of expressions in the array initializer. Для многомерного массива т. е. один where rank_specifier содержит по крайней мере одна запятая этот набор включает в себя все выражениеs из вложенных array_initializers.For a multidimensional array, i.e., one where the rank_specifier contains at least one comma, this set comprises all expressions found in nested array_initializers.

Инициализаторы массивов описаны далее в Инициализаторы массивов.Array initializers are described further in Array initializers.

Результат вычисления выражения создания массива классифицируется как значение, а именно: ссылка на экземпляр вновь выделенный массив.The result of evaluating an array creation expression is classified as a value, namely a reference to the newly allocated array instance. Во время выполнения обработки выражение создания массива состоит из следующих действий:The run-time processing of an array creation expression consists of the following steps:

  • Длина выражения измерений список_выражений вычисляются в порядке слева направо.The dimension length expressions of the expression_list are evaluated in order, from left to right. После вычисления каждого выражения, неявное преобразование (неявные преобразования) выполняется одно из следующих типов: int, uint, long, ulong.Following evaluation of each expression, an implicit conversion (Implicit conversions) to one of the following types is performed: int, uint, long, ulong. Будет выбран первый тип, в этом списке, для которого существует неявное преобразование.The first type in this list for which an implicit conversion exists is chosen. Если вычисление выражения или последующих неявное преобразование возникает исключение, следующие выражения оцениваются, и никакие дополнительные действия выполняются.If evaluation of an expression or the subsequent implicit conversion causes an exception, then no further expressions are evaluated and no further steps are executed.
  • Вычисленные значения для длины по измерениям проверяются следующим образом.The computed values for the dimension lengths are validated as follows. Если один или несколько значений меньше нуля, System.OverflowException возникает исключение и никакие дополнительные действия не выполняются.If one or more of the values are less than zero, a System.OverflowException is thrown and no further steps are executed.
  • Выделяется экземпляр массива с заданной длины по измерениям.An array instance with the given dimension lengths is allocated. Если не хватает памяти для выделения нового экземпляра, System.OutOfMemoryException возникает исключение и никакие дополнительные действия не выполняются.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
  • Все элементы нового экземпляра массива инициализируются значениями по умолчанию (значения по умолчанию).All elements of the new array instance are initialized to their default values (Default values).
  • Если выражение создания массива содержит инициализатор массива, каждое выражение в инициализаторе массива вычисляются и присваиваются соответствующим элементом массива.If the array creation expression contains an array initializer, then each expression in the array initializer is evaluated and assigned to its corresponding array element. Вычисления и присваивания выполняются в порядке, при написании выражения в инициализаторе массива — другими словами, элементы инициализируются в порядке по возрастанию индекса, с самого правого измерения, первым.The evaluations and assignments are performed in the order the expressions are written in the array initializer—in other words, elements are initialized in increasing index order, with the rightmost dimension increasing first. Если вычисления данного выражения или последующем присваивании в соответствующий элемент массива приводит к возникновению исключения, последующих элементов не инициализируются (и остальные элементы таким образом будут иметь значения по умолчанию).If evaluation of a given expression or the subsequent assignment to the corresponding array element causes an exception, then no further elements are initialized (and the remaining elements will thus have their default values).

Выражение создания массива разрешает создание экземпляра массива с элементами типа массива, но элементы такого массива должны инициализироваться вручную.An array creation expression permits instantiation of an array with elements of an array type, but the elements of such an array must be manually initialized. Например инструкцияFor example, the statement

int[][] a = new int[100][];

Создает одномерный массив с 100 элементов типа int[].creates a single-dimensional array with 100 elements of type int[]. Начальное значение каждого элемента является null.The initial value of each element is null. Невозможно для же выражение создания массива инициализировать подмассивов и инструкцииIt is not possible for the same array creation expression to also instantiate the sub-arrays, and the statement

int[][] a = new int[100][5];        // Error

приводит к ошибке времени компиляции.results in a compile-time error. При создании экземпляра подмассивов вместо должна выполняться вручную, как и вInstantiation of the sub-arrays must instead be performed manually, as in

int[][] a = new int[100][];
for (int i = 0; i < 100; i++) a[i] = new int[5];

Массив массивов имеет форму «прямоугольная», то есть когда вложенные массивы имеют одинаковую длину, при более эффективно использовать многомерный массив.When an array of arrays has a "rectangular" shape, that is when the sub-arrays are all of the same length, it is more efficient to use a multi-dimensional array. В приведенном выше примере при инициализации массива массивов создается 101 объект — один внешний массив и 100 вложенных массивов.In the example above, instantiation of the array of arrays creates 101 objects—one outer array and 100 sub-arrays. Напротив,In contrast,

int[,] = new int[100, 5];

создает только один объект, двумерный массив и выполняет распределение в одной инструкции.creates only a single object, a two-dimensional array, and accomplishes the allocation in a single statement.

Ниже приведены примеры выражений создание неявно типизированного массива:The following are examples of implicitly typed array creation expressions:

var a = new[] { 1, 10, 100, 1000 };                       // int[]

var b = new[] { 1, 1.5, 2, 2.5 };                         // double[]

var c = new[,] { { "hello", null }, { "world", "!" } };   // string[,]

var d = new[] { 1, "one", 2, "two" };                     // Error

Последнее выражение вызывает ошибку времени компиляции, поскольку ни int , ни string может быть неявно преобразован в другой и введите там нет, наиболее часто.The last expression causes a compile-time error because neither int nor string is implicitly convertible to the other, and so there is no best common type. Выражение создания массива явным образом типизированной необходимо использовать таким образом, например указав используется тип object[].An explicitly typed array creation expression must be used in this case, for example specifying the type to be object[]. Кроме того один из элементов можно привести к общему базовому типу, который затем станет выведенным типом элемента.Alternatively, one of the elements can be cast to a common base type, which would then become the inferred element type.

Неявно типизированный массив создания выражения можно объединить с помощью инициализатора анонимных объектов (выражения создания анонимных объектов) для создания анонимно типизированных структур данных.Implicitly typed array creation expressions can be combined with anonymous object initializers (Anonymous object creation expressions) to create anonymously typed data structures. Пример:For example:

var contacts = new[] {
    new {
        Name = "Chris Smith",
        PhoneNumbers = new[] { "206-555-0101", "425-882-8080" }
    },
    new {
        Name = "Bob Harris",
        PhoneNumbers = new[] { "650-555-0199" }
    }
};

Выражения создания делегатаDelegate creation expressions

Объект delegate_creation_expression используется для создания нового экземпляра delegate_type.A delegate_creation_expression is used to create a new instance of a delegate_type.

delegate_creation_expression
    : 'new' delegate_type '(' expression ')'
    ;

Аргумент выражения создания делегата должен быть группу методов, анонимная функция или значение типа времени компиляции dynamic или delegate_type.The argument of a delegate creation expression must be a method group, an anonymous function or a value of either the compile time type dynamic or a delegate_type. Если аргумент представляет группу методов, он определяет метод и метод экземпляра, объект, для которого создается делегат.If the argument is a method group, it identifies the method and, for an instance method, the object for which to create a delegate. Если аргумент представляет собой анонимную функцию непосредственно определяет параметры и тело метода целевого делегата.If the argument is an anonymous function it directly defines the parameters and method body of the delegate target. Если аргумент имеет значение, он определяет экземпляр делегата, для которого необходимо создать копию.If the argument is a value it identifies a delegate instance of which to create a copy.

Если выражение имеет тип времени компиляции dynamic, delegate_creation_expression является динамическим (динамической привязки) и правил, приведенных ниже применяются во время выполнения, используя тип среды выполнения выражение.If the expression has the compile-time type dynamic, the delegate_creation_expression is dynamically bound (Dynamic binding), and the rules below are applied at run-time using the run-time type of the expression. В противном случае правила применяются во время компиляции.Otherwise the rules are applied at compile-time.

Во время привязки обработка delegate_creation_expression формы new D(E), где Ddelegate_type и Eвыражение , состоит из следующих действий:The binding-time processing of a delegate_creation_expression of the form new D(E), where D is a delegate_type and E is an expression, consists of the following steps:

  • Если E является группой методов выражения создания делегата обрабатывается так же, как преобразования группы методов (преобразования групп методов) из E для D.If E is a method group, the delegate creation expression is processed in the same way as a method group conversion (Method group conversions) from E to D.
  • Если E является анонимной функцией, выражение создания делегата обрабатывается так же, как преобразование анонимной функции (преобразования анонимных функций) из E для D.If E is an anonymous function, the delegate creation expression is processed in the same way as an anonymous function conversion (Anonymous function conversions) from E to D.
  • Если E является значением, E должно быть совместимо (объявления делегатов) с D, и результатом является ссылкой на только что созданный делегат типа D , ссылающийся на вызовов в списке E.If E is a value, E must be compatible (Delegate declarations) with D, and the result is a reference to a newly created delegate of type D that refers to the same invocation list as E. Если E не совместим с D, возникает ошибка времени компиляции.If E is not compatible with D, a compile-time error occurs.

Во время выполнения обработки delegate_creation_expression формы new D(E), где Ddelegate_type и Eвыражение , состоит из следующих действий:The run-time processing of a delegate_creation_expression of the form new D(E), where D is a delegate_type and E is an expression, consists of the following steps:

  • Если E является группой методов выражения создания делегата вычисляется как преобразования группы методов (преобразования групп методов) из E для D.If E is a method group, the delegate creation expression is evaluated as a method group conversion (Method group conversions) from E to D.
  • Если E представляет собой анонимную функцию создания делегата обрабатывается как преобразование анонимной функции из E для D (преобразования анонимных функций).If E is an anonymous function, the delegate creation is evaluated as an anonymous function conversion from E to D (Anonymous function conversions).
  • Если E представляет собой значение delegate_type:If E is a value of a delegate_type:
    • E выполняется оценка.E is evaluated. Если эта оценка вызывает исключение, никакие дополнительные действия выполняются.If this evaluation causes an exception, no further steps are executed.
    • Если значение Enull, System.NullReferenceException возникает исключение и никакие дополнительные действия не выполняются.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • Новый экземпляр типа делегата D выделяется.A new instance of the delegate type D is allocated. Если не хватает памяти для выделения нового экземпляра, System.OutOfMemoryException возникает исключение и никакие дополнительные действия не выполняются.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • Новый экземпляр делегата инициализируется с такой же список вызова, как экземпляр делегата, выданный E.The new delegate instance is initialized with the same invocation list as the delegate instance given by E.

Список вызовов делегата определяется при создании экземпляра делегата и остается неизменным в течение всего времени существования делегата.The invocation list of a delegate is determined when the delegate is instantiated and then remains constant for the entire lifetime of the delegate. Другими словами не сможете изменить целевые вызываемые сущности делегата после его создания.In other words, it is not possible to change the target callable entities of a delegate once it has been created. При объединении двух делегатов или удалении одного из другого (объявления делегатов), результаты новый делегат, не существующий делегат имеет его содержимое изменены.When two delegates are combined or one is removed from another (Delegate declarations), a new delegate results; no existing delegate has its contents changed.

Это не позволяет создать делегат, который ссылается на свойство, индексатор, определяемого пользователем оператора, конструктор экземпляра, деструктор или статический конструктор.It is not possible to create a delegate that refers to a property, indexer, user-defined operator, instance constructor, destructor, or static constructor.

Как описано выше, если делегат создается из группы методов, список формальных параметров и тип возвращаемого значения делегата определить, какой из перегруженных методов для выбора.As described above, when a delegate is created from a method group, the formal parameter list and return type of the delegate determine which of the overloaded methods to select. В примереIn the example

delegate double DoubleFunc(double x);

class A
{
    DoubleFunc f = new DoubleFunc(Square);

    static float Square(float x) {
        return x * x;
    }

    static double Square(double x) {
        return x * x;
    }
}

A.f поле инициализируется с делегатом, который ссылается на второй Square метод, так как этот метод точно соответствует списку формальных параметров и тип возвращаемого значения DoubleFunc.the A.f field is initialized with a delegate that refers to the second Square method because that method exactly matches the formal parameter list and return type of DoubleFunc. Второй Square отсутствует, во время компиляции возникает ошибка.Had the second Square method not been present, a compile-time error would have occurred.

Выражения создания анонимных объектовAnonymous object creation expressions

Anonymous_object_creation_expression используется для создания объекта анонимного типа.An anonymous_object_creation_expression is used to create an object of an anonymous type.

anonymous_object_creation_expression
    : 'new' anonymous_object_initializer
    ;

anonymous_object_initializer
    : '{' member_declarator_list? '}'
    | '{' member_declarator_list ',' '}'
    ;

member_declarator_list
    : member_declarator (',' member_declarator)*
    ;

member_declarator
    : simple_name
    | member_access
    | base_access
    | null_conditional_member_access
    | identifier '=' expression
    ;

Инициализатор анонимного объекта объявляет анонимный тип и возвращает экземпляр этого типа.An anonymous object initializer declares an anonymous type and returns an instance of that type. Анонимный тип является типом безымянного класса, который напрямую наследует от object.An anonymous type is a nameless class type that inherits directly from object. Члены анонимного типа представляют собой последовательность свойств только для чтения, которые получены из инициализатора анонимный объект, используемый для создания экземпляра типа.The members of an anonymous type are a sequence of read-only properties inferred from the anonymous object initializer used to create an instance of the type. В частности инициализатор анонимного объекта формыSpecifically, an anonymous object initializer of the form

new { p1 = e1, p2 = e2, ..., pn = en }

Объявляет анонимный тип формыdeclares an anonymous type of the form

class __Anonymous1
{
    private readonly T1 f1;
    private readonly T2 f2;
    ...
    private readonly Tn fn;

    public __Anonymous1(T1 a1, T2 a2, ..., Tn an) {
        f1 = a1;
        f2 = a2;
        ...
        fn = an;
    }

    public T1 p1 { get { return f1; } }
    public T2 p2 { get { return f2; } }
    ...
    public Tn pn { get { return fn; } }

    public override bool Equals(object __o) { ... }
    public override int GetHashCode() { ... }
}

где каждый Tx — это тип соответствующее выражение ex.where each Tx is the type of the corresponding expression ex. Выражение, используемое в member_declarator должно иметь тип.The expression used in a member_declarator must have a type. Таким образом, это ошибка времени компиляции для выражения в member_declarator быть null или анонимной функции.Thus, it is a compile-time error for an expression in a member_declarator to be null or an anonymous function. Это также ошибка времени компиляции иметь небезопасный тип выражения.It is also a compile-time error for the expression to have an unsafe type.

Имена анонимного типа и параметра для его Equals метод автоматически создаются компилятором и нельзя ссылаться в тексте программы.The names of an anonymous type and of the parameter to its Equals method are automatically generated by the compiler and cannot be referenced in program text.

В той же программе два инициализатора анонимных объектов, указывающих последовательность свойств одинаковые имена и типы времени компиляции, в том же порядке, будут создавать экземпляры того же анонимного типа.Within the same program, two anonymous object initializers that specify a sequence of properties of the same names and compile-time types in the same order will produce instances of the same anonymous type.

В примереIn the example

var p1 = new { Name = "Lawnmower", Price = 495.00 };
var p2 = new { Name = "Shovel", Price = 26.95 };
p1 = p2;

Назначение в последней строке разрешен, так как p1 и p2 имеют одинаковый анонимный тип.the assignment on the last line is permitted because p1 and p2 are of the same anonymous type.

Equals И GetHashcode методы в анонимных типах переопределить эти методы, унаследованные от objectи определяются на основе Equals и GetHashcode свойства, таким образом, чтобы два экземпляра одного анонимного типа равны Если и только в том случае, если равны их свойства.The Equals and GetHashcode methods on anonymous types override the methods inherited from object, and are defined in terms of the Equals and GetHashcode of the properties, so that two instances of the same anonymous type are equal if and only if all their properties are equal.

Объявление члена можно сократить до простого имени (вывод типа), доступ к членам (Проверка динамического разрешения перегрузки во время компиляции), доступ к базовым членам (базового доступа) или доступ к члену с условием null (выражения условием Null как инициализаторы проекций).A member declarator can be abbreviated to a simple name (Type inference), a member access (Compile-time checking of dynamic overload resolution), a base access (Base access) or a null-conditional member access (Null-conditional expressions as projection initializers). Это называется инициализации проекции и является сокращением для объявления и назначения к свойству с тем же именем.This is called a projection initializer and is shorthand for a declaration of and assignment to a property with the same name. В частности деклараторы элементов из формSpecifically, member declarators of the forms

identifier
expr.identifier

будут точными эквивалентами следующих, соответственно:are precisely equivalent to the following, respectively:

identifier = identifier
identifier = expr.identifier

Таким образом, при инициализации проекции идентификатор выбирает как значение и поле или свойство, которому присваивается значение.Thus, in a projection initializer the identifier selects both the value and the field or property to which the value is assigned. Интуитивно понятным образом инициализатор проекции проектов не только значение, а также имя параметра.Intuitively, a projection initializer projects not just a value, but also the name of the value.

Оператор typeofThe typeof operator

typeof Оператор используется для получения System.Type объекта для типа.The typeof operator is used to obtain the System.Type object for a type.

typeof_expression
    : 'typeof' '(' type ')'
    | 'typeof' '(' unbound_type_name ')'
    | 'typeof' '(' 'void' ')'
    ;

unbound_type_name
    : identifier generic_dimension_specifier?
    | identifier '::' identifier generic_dimension_specifier?
    | unbound_type_name '.' identifier generic_dimension_specifier?
    ;

generic_dimension_specifier
    : '<' comma* '>'
    ;

comma
    : ','
    ;

В первой форме typeof_expression состоит из typeof ключевое слово и заключенные в круглые скобки тип.The first form of typeof_expression consists of a typeof keyword followed by a parenthesized type. Результатом выражения этой формы является System.Type объект для определенного типа.The result of an expression of this form is the System.Type object for the indicated type. Имеется только один System.Type объекта для любого типа.There is only one System.Type object for any given type. Это означает, что для типа T, typeof(T) == typeof(T) всегда имеет значение true.This means that for a type T, typeof(T) == typeof(T) is always true. Тип не может быть dynamic.The type cannot be dynamic.

Вторая форма typeof_expression состоит из typeof ключевое слово и заключенные в круглые скобки unbound_type_name.The second form of typeof_expression consists of a typeof keyword followed by a parenthesized unbound_type_name. Unbound_type_name очень похожа на type_name (пространства имен и тип) за исключением того, что unbound_type_name содержит generic_dimension_specifiers где type_name содержит type_argument_lists.An unbound_type_name is very similar to a type_name (Namespace and type names) except that an unbound_type_name contains generic_dimension_specifiers where a type_name contains type_argument_lists. Когда операнд typeof_expression представляет собой последовательность токенов, удовлетворяющий грамматики обоих unbound_type_name и type_name, а именно при нем ни generic_dimension_specifier ни type_argument_list, рассматривается как последовательность токенов type_name.When the operand of a typeof_expression is a sequence of tokens that satisfies the grammars of both unbound_type_name and type_name, namely when it contains neither a generic_dimension_specifier nor a type_argument_list, the sequence of tokens is considered to be a type_name. Значение unbound_type_name определяется следующим образом:The meaning of an unbound_type_name is determined as follows:

  • Преобразовать последовательность токенов type_name путем замены каждой generic_dimension_specifier с type_argument_list с таким же числом запятых и Ключевое слово object каждого type_argument.Convert the sequence of tokens to a type_name by replacing each generic_dimension_specifier with a type_argument_list having the same number of commas and the keyword object as each type_argument.
  • Оцените итоговый type_name, игнорируя все ограничения параметра типа.Evaluate the resulting type_name, while ignoring all type parameter constraints.
  • Unbound_type_name разрешается несвязанного универсального типа, связанный с итоговый сконструированный тип (привязан и несвязанные типы).The unbound_type_name resolves to the unbound generic type associated with the resulting constructed type (Bound and unbound types).

Результат typeof_expression является System.Type объект, полученный в результате непривязанным универсального типа.The result of the typeof_expression is the System.Type object for the resulting unbound generic type.

Третья форма из typeof_expression состоит из typeof ключевое слово и заключенные в круглые скобки void ключевое слово.The third form of typeof_expression consists of a typeof keyword followed by a parenthesized void keyword. Результатом выражения этой формы является System.Type объект, представляющий отсутствие типа.The result of an expression of this form is the System.Type object that represents the absence of a type. Тип объекта, возвращаемого typeof(void) отличается от объекта типа, возвращаемого для любого типа.The type object returned by typeof(void) is distinct from the type object returned for any type. Этот специальный объект типа полезно в библиотеках классов, которые допускают отражение в методы на языке, где этих методов желательно иметь способ представления типа возвращаемого значения, включая void методы, с помощью экземпляра System.Type.This special type object is useful in class libraries that allow reflection onto methods in the language, where those methods wish to have a way to represent the return type of any method, including void methods, with an instance of System.Type.

typeof Оператор может использоваться для параметра типа.The typeof operator can be used on a type parameter. В результате System.Type объект типа времени выполнения, который был привязан к параметру типа.The result is the System.Type object for the run-time type that was bound to the type parameter. typeof Оператор также может использоваться для сконструированного типа или несвязанного универсального типа (привязан и несвязанные типы).The typeof operator can also be used on a constructed type or an unbound generic type (Bound and unbound types). System.Type Объекта для несвязанного универсального типа не является таким же, как System.Type объект типа экземпляра.The System.Type object for an unbound generic type is not the same as the System.Type object of the instance type. Тип экземпляра всегда является закрытым сконструированным типом во время выполнения таким образом его System.Type объект зависит от выполнения аргументов типа, хотя несвязанного универсального типа не имеет типа аргументов.The instance type is always a closed constructed type at run-time so its System.Type object depends on the run-time type arguments in use, while the unbound generic type has no type arguments.

ПримерThe example

using System;

class X<T>
{
    public static void PrintTypes() {
        Type[] t = {
            typeof(int),
            typeof(System.Int32),
            typeof(string),
            typeof(double[]),
            typeof(void),
            typeof(T),
            typeof(X<T>),
            typeof(X<X<T>>),
            typeof(X<>)
        };
        for (int i = 0; i < t.Length; i++) {
            Console.WriteLine(t[i]);
        }
    }
}

class Test
{
    static void Main() {
        X<int>.PrintTypes();
    }
}

получается следующий результат:produces the following output:

System.Int32
System.Int32
System.String
System.Double[]
System.Void
System.Int32
X`1[System.Int32]
X`1[X`1[System.Int32]]
X`1[T]

Обратите внимание, что int и System.Int32 относятся к одному типу.Note that int and System.Int32 are the same type.

Также Обратите внимание, что результат typeof(X<>) не зависит от аргумента типа, а результат typeof(X<T>) does.Also note that the result of typeof(X<>) does not depend on the type argument but the result of typeof(X<T>) does.

Операторы checked и uncheckedThe checked and unchecked operators

checked И unchecked операторы используются для управления контекстом проверки переполнения для целочисленных арифметических операций и преобразований.The checked and unchecked operators are used to control the overflow checking context for integral-type arithmetic operations and conversions.

checked_expression
    : 'checked' '(' expression ')'
    ;

unchecked_expression
    : 'unchecked' '(' expression ')'
    ;

checked Оператор вычисляет выражение, содержащиеся в проверяемом контексте и unchecked оператор вычисляет содержащегося выражения в непроверенном контексте.The checked operator evaluates the contained expression in a checked context, and the unchecked operator evaluates the contained expression in an unchecked context. Объект checked_expression или unchecked_expression в точности соответствует parenthesized_expression (выражения в скобках), за исключением того, что автономной выражение вычисляется в заданной контекста проверки переполнения.A checked_expression or unchecked_expression corresponds exactly to a parenthesized_expression (Parenthesized expressions), except that the contained expression is evaluated in the given overflow checking context.

Контекст проверки переполнения можно также управлять с помощью checked и unchecked инструкций (операторы checked и unchecked).The overflow checking context can also be controlled through the checked and unchecked statements (The checked and unchecked statements).

Следующие операции зависят от контекста, опубликованный консорциумом проверки переполнения checked и unchecked операторы и операторы:The following operations are affected by the overflow checking context established by the checked and unchecked operators and statements:

Когда один из указанных выше операций произвести результат, слишком велико для представления в целевом типе, контекст, в котором операция управляет результирующее поведение:When one of the above operations produce a result that is too large to represent in the destination type, the context in which the operation is performed controls the resulting behavior:

  • В checked контекста, если операция является константным выражением (константные выражения), возникает ошибка времени компиляции.In a checked context, if the operation is a constant expression (Constant expressions), a compile-time error occurs. В противном случае, когда выполняется операция во время выполнения, System.OverflowException возникает исключение.Otherwise, when the operation is performed at run-time, a System.OverflowException is thrown.
  • В unchecked контекста, результат усекается путем удаления старших разрядов, которые не помещаются в целевой тип.In an unchecked context, the result is truncated by discarding any high-order bits that do not fit in the destination type.

Для Неконстантные выражения (выражения, которые вычисляются во время выполнения), которые не заключаются по любому checked или unchecked операторы или операторы, контекстом проверки переполнения по умолчанию является unchecked Если внешние факторы (например, компилятор Переключение и конфигурацией среды выполнения) вызвать для checked оценки.For non-constant expressions (expressions that are evaluated at run-time) that are not enclosed by any checked or unchecked operators or statements, the default overflow checking context is unchecked unless external factors (such as compiler switches and execution environment configuration) call for checked evaluation.

Относительно константных выражений (выражения, которые можно полностью вычислить во время компиляции), всегда является контекстом проверки переполнения по умолчанию checked.For constant expressions (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked. Если константное выражение явным образом помещается в unchecked контекста, переполнения, возникающие во время компиляции вычисления выражения всегда вызывать ошибки времени компиляции.Unless a constant expression is explicitly placed in an unchecked context, overflows that occur during the compile-time evaluation of the expression always cause compile-time errors.

Тело анонимной функции не зависит от checked или unchecked контексты, в которых происходит анонимной функции.The body of an anonymous function is not affected by checked or unchecked contexts in which the anonymous function occurs.

В примереIn the example

class Test
{
    static readonly int x = 1000000;
    static readonly int y = 1000000;

    static int F() {
        return checked(x * y);      // Throws OverflowException
    }

    static int G() {
        return unchecked(x * y);    // Returns -727379968
    }

    static int H() {
        return x * y;               // Depends on default
    }
}

ошибки компиляции не выводятся, поскольку ни одно из выражений может быть вычислено во время компиляции.no compile-time errors are reported since neither of the expressions can be evaluated at compile-time. Во время выполнения F вызывает метод System.OverflowExceptionи G метод возвращает-727379968 (младшие 32 бита результата out of range).At run-time, the F method throws a System.OverflowException, and the G method returns -727379968 (the lower 32 bits of the out-of-range result). Поведение H метод зависит от контекста для компиляции проверки переполнения по умолчанию, но это либо совпадает F или так же, как G.The behavior of the H method depends on the default overflow checking context for the compilation, but it is either the same as F or the same as G.

В примереIn the example

class Test
{
    const int x = 1000000;
    const int y = 1000000;

    static int F() {
        return checked(x * y);      // Compile error, overflow
    }

    static int G() {
        return unchecked(x * y);    // Returns -727379968
    }

    static int H() {
        return x * y;               // Compile error, overflow
    }
}

переполнения, возникающие при вычислении константных выражений в F и H привести к ошибкам во время компиляции, потому что выражения вычисляются в checked контекста.the overflows that occur when evaluating the constant expressions in F and H cause compile-time errors to be reported because the expressions are evaluated in a checked context. Также может произойти переполнение при вычислении константного выражения в G, но поскольку вычисление выполняется unchecked контекста, переполнение не сообщается.An overflow also occurs when evaluating the constant expression in G, but since the evaluation takes place in an unchecked context, the overflow is not reported.

checked И unchecked операторы влияют только на контекст для тех операций, содержащихся в текстовой форме проверки переполнения "(«и»)" маркеров.The checked and unchecked operators only affect the overflow checking context for those operations that are textually contained within the "(" and ")" tokens. Операторы не оказывают влияния на функции-члены, которые будут вызываться в результате вычисления выражения автономной.The operators have no effect on function members that are invoked as a result of evaluating the contained expression. В примереIn the example

class Test
{
    static int Multiply(int x, int y) {
        return x * y;
    }

    static int F() {
        return checked(Multiply(1000000, 1000000));
    }
}

Использование checked в F не влияет на вычисления x * y в Multiply, поэтому x * y вычисляется в контекст проверки переполнения по умолчанию.the use of checked in F does not affect the evaluation of x * y in Multiply, so x * y is evaluated in the default overflow checking context.

unchecked Оператор удобно при написании константы целочисленных типов со знаком в шестнадцатеричном формате.The unchecked operator is convenient when writing constants of the signed integral types in hexadecimal notation. Пример:For example:

class Test
{
    public const int AllBits = unchecked((int)0xFFFFFFFF);

    public const int HighBit = unchecked((int)0x80000000);
}

Оба шестнадцатеричные константы выше относятся к типу uint.Both of the hexadecimal constants above are of type uint. Так как используются следующие константы за пределами int диапазон "," без unchecked оператор, приведения в int будет приводить к ошибкам компиляции.Because the constants are outside the int range, without the unchecked operator, the casts to int would produce compile-time errors.

checked И unchecked операторы и операторы позволяют программистам управлять некоторыми аспектами некоторых числовых вычислений.The checked and unchecked operators and statements allow programmers to control certain aspects of some numeric calculations. Тем не менее поведение некоторых числовых операторов зависит от типов данных их операндов.However, the behavior of some numeric operators depends on their operands' data types. Например, умножение двух десятичных чисел всегда вызывает исключение в случае переполнения даже в явно unchecked построения.For example, multiplying two decimals always results in an exception on overflow even within an explicitly unchecked construct. Аналогичным образом, умножение двух смещает никогда не результатов в исключение в случае переполнения даже в явно checked построения.Similarly, multiplying two floats never results in an exception on overflow even within an explicitly checked construct. Кроме того, другие операторы никогда не затрагивает режимом проверки, как по умолчанию или неявным.In addition, other operators are never affected by the mode of checking, whether default or explicit.

Выражения значения по умолчаниюDefault value expressions

Выражение значения по умолчанию используется для получения значения по умолчанию (значения по умолчанию) типа.A default value expression is used to obtain the default value (Default values) of a type. Обычно выражение значения по умолчанию используется для параметров типа, так как он не может быть известен, если параметр типа является типом значения или ссылочным типом.Typically a default value expression is used for type parameters, since it may not be known if the type parameter is a value type or a reference type. (Не существует преобразования из null литерала к параметру типа, если не известно, параметр типа ссылочным типом.)(No conversion exists from the null literal to a type parameter unless the type parameter is known to be a reference type.)

default_value_expression
    : 'default' '(' type ')'
    ;

Если тип в default_value_expression оценивает во время выполнения для ссылочного типа, результатом является null привести к этому типу.If the type in a default_value_expression evaluates at run-time to a reference type, the result is null converted to that type. Если тип в default_value_expression оценивает во время выполнения к типу значения, результатом является value_typeзначение по умолчанию (по умолчанию конструкторы).If the type in a default_value_expression evaluates at run-time to a value type, the result is the value_type's default value (Default constructors).

Объект default_value_expression является константным выражением (константные выражения) Если тип является ссылочным типом или параметром типа, который известен быть ссылочным типом (параметр типа ограничения).A default_value_expression is a constant expression (Constant expressions) if the type is a reference type or a type parameter that is known to be a reference type (Type parameter constraints). Кроме того default_value_expression является константным выражением, в том случае, если тип является одним из следующих типов значений: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, или любой тип перечисления.In addition, a default_value_expression is a constant expression if the type is one of the following value types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, or any enumeration type.

Выражения NameofNameof expressions

Объект nameof_expression используется для получения имени сущность программы как строковую константу.A nameof_expression is used to obtain the name of a program entity as a constant string.

nameof_expression
    : 'nameof' '(' named_entity ')'
    ;

named_entity
    : simple_name
    | named_entity_target '.' identifier type_argument_list?
    ;

named_entity_target
    : 'this'
    | 'base'
    | named_entity 
    | predefined_type 
    | qualified_alias_member
    ;

Грамматически говоря, named_entity операнд всегда представляет собой выражение.Grammatically speaking, the named_entity operand is always an expression. Так как nameof не является зарезервированным ключевым словом выражения nameof всегда синтаксически неоднозначно в вызов простое имя nameof.Because nameof is not a reserved keyword, a nameof expression is always syntactically ambiguous with an invocation of the simple name nameof. По причинам совместимости, если при поиске имени (простые имена) с именем nameof завершается успешно, выражение рассматривается как invocation_expression — независимо от того, является ли вызов Юридические.For compatibility reasons, if a name lookup (Simple names) of the name nameof succeeds, the expression is treated as an invocation_expression -- regardless of whether the invocation is legal. В противном случае это nameof_expression.Otherwise it is a nameof_expression.

Значение named_entity из nameof_expression означает его как выражение; то есть, либо как simple_name, base_access или member_access.The meaning of the named_entity of a nameof_expression is the meaning of it as an expression; that is, either as a simple_name, a base_access or a member_access. Тем не менее, где поиска описано в разделе простые имена и доступ к членам приводит к ошибке, так как член экземпляра был найден в статическом контексте nameof_expressionсоздает ошибки не.However, where the lookup described in Simple names and Member access results in an error because an instance member was found in a static context, a nameof_expression produces no such error.

Произошла ошибка во время компиляции для named_entity обозначающий группу методов, чтобы type_argument_list.It is a compile-time error for a named_entity designating a method group to have a type_argument_list. Это ошибка времени компиляции для named_entity_target как имеющие тип dynamic.It is a compile time error for a named_entity_target to have the type dynamic.

Объект nameof_expression — это константное выражение типа string, и не оказывает влияния во время выполнения.A nameof_expression is a constant expression of type string, and has no effect at runtime. В частности его named_entity не вычисляется и учитывается для целей анализа определенного присваивания (общие правила для простых выражений).Specifically, its named_entity is not evaluated, and is ignored for the purposes of definite assignment analysis (General rules for simple expressions). Его значение является идентификатором последнего named_entity необязательно окончательной type_argument_list, преобразованные следующим образом:Its value is the last identifier of the named_entity before the optional final type_argument_list, transformed in the following way:

  • Префикс "@«, если используется, удаляется.The prefix "@", if used, is removed.
  • Каждый unicode_escape_sequence преобразуется в соответствующий символ Юникода.Each unicode_escape_sequence is transformed into its corresponding Unicode character.
  • Любой formatting_characters удаляются.Any formatting_characters are removed.

Это те же преобразования, примененные в идентификаторы при тестировании равенства между идентификаторами.These are the same transformations applied in Identifiers when testing equality between identifiers.

TODO: примерыTODO: examples

Выражения анонимного методаAnonymous method expressions

Anonymous_method_expression является одним из двух способов определения анонимной функции.An anonymous_method_expression is one of two ways of defining an anonymous function. Более подробно они описаны в выражения анонимных функций.These are further described in Anonymous function expressions.

Унарные операторыUnary operators

?, +, -, !, ~, ++, --, Приведите, и await называются унарные операторы.The ?, +, -, !, ~, ++, --, cast, and await operators are called the unary operators.

unary_expression
    : primary_expression
    | null_conditional_expression
    | '+' unary_expression
    | '-' unary_expression
    | '!' unary_expression
    | '~' unary_expression
    | pre_increment_expression
    | pre_decrement_expression
    | cast_expression
    | await_expression
    | unary_expression_unsafe
    ;

Если операнд unary_expression имеет тип времени компиляции dynamic, он является динамическим (динамической привязки).If the operand of a unary_expression has the compile-time type dynamic, it is dynamically bound (Dynamic binding). В этом случае тип времени компиляции unary_expression является dynamic, а разрешение, приведенное ниже будет иметь место во время выполнения, используя тип времени выполнения операнда.In this case the compile-time type of the unary_expression is dynamic, and the resolution described below will take place at run-time using the run-time type of the operand.

Условного оператораNull-conditional operator

Условного оператора применяется список операций для своего операнда, только в том случае, если этот операнд не равно null.The null-conditional operator applies a list of operations to its operand only if that operand is non-null. В противном случае результатом применения оператора является null.Otherwise the result of applying the operator is null.

null_conditional_expression
    : primary_expression null_conditional_operations
    ;

null_conditional_operations
    : null_conditional_operations? '?' '.' identifier type_argument_list?
    | null_conditional_operations? '?' '[' argument_list ']'
    | null_conditional_operations '.' identifier type_argument_list?
    | null_conditional_operations '[' argument_list ']'
    | null_conditional_operations '(' argument_list? ')'
    ;

Список операций можно включить доступ к членам и операции с элементами доступа (которые могут быть условием null), а также вызова.The list of operations can include member access and element access operations (which may themselves be null-conditional), as well as invocation.

Например, выражение a.b?[0]?.c()null_conditional_expression с primary_expression a.b и null_conditional_operations ?[0] (доступ к элементам с условием null), ?.c (доступ к членам условием null) и () (вызов).For example, the expression a.b?[0]?.c() is a null_conditional_expression with a primary_expression a.b and null_conditional_operations ?[0] (null-conditional element access), ?.c (null-conditional member access) and () (invocation).

Для null_conditional_expression E с primary_expression P, позволяют E0 быть выражением, полученные в текстовой форме, удалив в начале ?от каждого из null_conditional_operations из E , имеющих одно.For a null_conditional_expression E with a primary_expression P, let E0 be the expression obtained by textually removing the leading ? from each of the null_conditional_operations of E that have one. По существу E0 — это выражение, которое должно быть вычислено, если ни одна из проверок значений null, представленный ?s найти null.Conceptually, E0 is the expression that will be evaluated if none of the null checks represented by the ?s do find a null.

Кроме того, предоставить E1 быть выражением, полученные в текстовой форме, удалив в начале ? из только первый из null_conditional_operations в E.Also, let E1 be the expression obtained by textually removing the leading ? from just the first of the null_conditional_operations in E. Это может привести к основное выражение (если он был только что ?) или на другой null_conditional_expression.This may lead to a primary-expression (if there was just one ?) or to another null_conditional_expression.

Например если E выражение a.b?[0]?.c(), затем E0 выражение a.b[0].c() и E1 выражение a.b[0]?.c().For example, if E is the expression a.b?[0]?.c(), then E0 is the expression a.b[0].c() and E1 is the expression a.b[0]?.c().

Если E0 классифицируется как nothing, затем E классифицируется как nothing.If E0 is classified as nothing, then E is classified as nothing. В противном случае E классифицируется как значение.Otherwise E is classified as a value.

E0 и E1 используются для определения значения E:E0 and E1 are used to determine the meaning of E:

  • Если E возникает как statement_expression значение E является таким же, как инструкцияIf E occurs as a statement_expression the meaning of E is the same as the statement

    if ((object)P != null) E1;
    

    за исключением того, что P вычисляется только один раз.except that P is evaluated only once.

  • В противном случае, если E0 классифицируется как ничего не происходит ошибка времени компиляции.Otherwise, if E0 is classified as nothing a compile-time error occurs.

  • В противном случае позволить T0 быть типом значения E0.Otherwise, let T0 be the type of E0.

    • Если T0 является параметром типа, быть ссылочным типом или типом значения, не допускающие значения NULL, возникает ошибка во время компиляции неизвестен.If T0 is a type parameter that is not known to be a reference type or a non-nullable value type, a compile-time error occurs.

    • Если T0 является типом значения, не допускающие значения NULL, то тип ET0?и значение E совпадает со значениемIf T0 is a non-nullable value type, then the type of E is T0?, and the meaning of E is the same as

      ((object)P == null) ? (T0?)null : E1
      

      за исключением того, что P вычисляется только один раз.except that P is evaluated only once.

    • В противном случае тип E — T0, а значение E — так же, какOtherwise the type of E is T0, and the meaning of E is the same as

      ((object)P == null) ? null : E1
      

      за исключением того, что P вычисляется только один раз.except that P is evaluated only once.

Если E1 сам null_conditional_expression, после чего эти правила применяются опять же, вложение тесты для null до более нет ?элемента, и выражение было сокращено вниз Чтобы основное выражение E0.If E1 is itself a null_conditional_expression, then these rules are applied again, nesting the tests for null until there are no further ?'s, and the expression has been reduced all the way down to the primary-expression E0.

Например если выражение a.b?[0]?.c() возникает как оператор выражение, AS в инструкции:For example, if the expression a.b?[0]?.c() occurs as a statement-expression, as in the statement:

a.b?[0]?.c();

его значение эквивалентно:its meaning is equivalent to:

if (a.b != null) a.b[0]?.c();

что еще раз эквивалентно:which again is equivalent to:

if (a.b != null) if (a.b[0] != null) a.b[0].c();

За исключением того, что a.b и a.b[0] вычисляются только один раз.Except that a.b and a.b[0] are evaluated only once.

Если он находится в контексте, где его значение используется, как в:If it occurs in a context where its value is used, as in:

var x = a.b?[0]?.c();

и Предположим, что тип последний вызов не является типом не поддерживающий значение NULL, его значение эквивалентно:and assuming that the type of the final invocation is not a non-nullable value type, its meaning is equivalent to:

var x = (a.b == null) ? null : (a.b[0] == null) ? null : a.b[0].c();

За исключением того, что a.b и a.b[0] вычисляются только один раз.except that a.b and a.b[0] are evaluated only once.

Выражения с условием NULL как инициализаторы проекцийNull-conditional expressions as projection initializers

Null условное выражение можно использовать только как member_declarator в anonymous_object_creation_expression (выражения создания анонимных объектов) Если заканчивается доступ к членам (при необходимости условием null).A null-conditional expression is only allowed as a member_declarator in an anonymous_object_creation_expression (Anonymous object creation expressions) if it ends with an (optionally null-conditional) member access. Грамматически это требование можно выразить следующим образом.Grammatically, this requirement can be expressed as:

null_conditional_member_access
    : primary_expression null_conditional_operations? '?' '.' identifier type_argument_list?
    | primary_expression null_conditional_operations '.' identifier type_argument_list?
    ;

Это особый случай грамматики для null_conditional_expression выше.This is a special case of the grammar for null_conditional_expression above. Производство для member_declarator в выражения создания анонимных объектов затем включает в себя только null_conditional_member_access.The production for member_declarator in Anonymous object creation expressions then includes only null_conditional_member_access.

Выражения условием NULL в качестве выражения с операторомNull-conditional expressions as statement expressions

Null условное выражение можно использовать только как statement_expression (операторы выражений), если оно станет вызовом.A null-conditional expression is only allowed as a statement_expression (Expression statements) if it ends with an invocation. Грамматически это требование можно выразить следующим образом.Grammatically, this requirement can be expressed as:

null_conditional_invocation_expression
    : primary_expression null_conditional_operations '(' argument_list? ')'
    ;

Это особый случай грамматики для null_conditional_expression выше.This is a special case of the grammar for null_conditional_expression above. Производство для statement_expression в операторы выражений затем включает в себя только null_conditional_invocation_expression.The production for statement_expression in Expression statements then includes only null_conditional_invocation_expression.

Оператор унарного сложенияUnary plus operator

Для операции в виде +x, разрешение перегрузки унарного оператора (разрешение перегрузки унарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form +x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Операнд преобразуется в тип параметра выбранного оператора и типом результата является тип возвращаемого значения оператора.The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. Предопределенные унарные и операторы являются:The predefined unary plus operators are:

int operator +(int x);
uint operator +(uint x);
long operator +(long x);
ulong operator +(ulong x);
float operator +(float x);
double operator +(double x);
decimal operator +(decimal x);

Для каждого из этих операторов результатом является просто значение операнда.For each of these operators, the result is simply the value of the operand.

Оператор унарного минусаUnary minus operator

Для операции в виде -x, разрешение перегрузки унарного оператора (разрешение перегрузки унарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form -x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Операнд преобразуется в тип параметра выбранного оператора и типом результата является тип возвращаемого значения оператора.The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. Ниже перечислены операторы предопределенные отрицания.The predefined negation operators are:

  • Отрицание целое число:Integer negation:

    int operator -(int x);
    long operator -(long x);
    

    Результат вычисляется путем вычитания x с нуля.The result is computed by subtracting x from zero. Если значение x является наименьшим представимым значением для типа операнда (-2 ^ 31 для int или -2 ^ 63 для long), затем математического отрицания x не может быть представлен в тип операнда.If the value of x is the smallest representable value of the operand type (-2^31 for int or -2^63 for long), then the mathematical negation of x is not representable within the operand type. В этом случае в checked контекста, System.OverflowException возникает исключение; если он встречается в unchecked контекст, результатом является значение операнда и о переполнении не сообщается.If this occurs within a checked context, a System.OverflowException is thrown; if it occurs within an unchecked context, the result is the value of the operand and the overflow is not reported.

    Если оператор отрицания операнд имеет тип uint, он преобразуется в тип long, а тип результата — long.If the operand of the negation operator is of type uint, it is converted to type long, and the type of the result is long. Исключением является правило, которое позволяет int значение от -2147483648 (-2 ^ 31) для записи в качестве Десятичный целочисленный литерал (Целочисленные литералы).An exception is the rule that permits the int value -2147483648 (-2^31) to be written as a decimal integer literal (Integer literals).

    Если оператор отрицания операнд имеет тип ulong, возникает ошибка времени компиляции.If the operand of the negation operator is of type ulong, a compile-time error occurs. Исключением является правило, которое позволяет long значение от -9223372036854775808 (-2 ^ 63) для записи в качестве Десятичный целочисленный литерал (Целочисленные литералы).An exception is the rule that permits the long value -9223372036854775808 (-2^63) to be written as a decimal integer literal (Integer literals).

  • С плавающей запятой отрицания:Floating-point negation:

    float operator -(float x);
    double operator -(double x);
    

    Результатом является значение x с обратным знаком.The result is the value of x with its sign inverted. Если x имеет значение NaN, результат также имеет значение NaN.If x is NaN, the result is also NaN.

  • Decimal отрицания:Decimal negation:

    decimal operator -(decimal x);
    

    Результат вычисляется путем вычитания x с нуля.The result is computed by subtracting x from zero. Равнозначно использованию унарный минус-оператор типа Decimal отрицания System.Decimal.Decimal negation is equivalent to using the unary minus operator of type System.Decimal.

Оператор логического отрицания:Logical negation operator

Для операции в виде !x, разрешение перегрузки унарного оператора (разрешение перегрузки унарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form !x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Операнд преобразуется в тип параметра выбранного оператора и типом результата является тип возвращаемого значения оператора.The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. Существует только один стандартный оператор логического отрицания:Only one predefined logical negation operator exists:

bool operator !(bool x);

Этот оператор вычисляет логическое отрицание операнда: Если операнд является true, в результате false.This operator computes the logical negation of the operand: If the operand is true, the result is false. Если операнд является false, в результате true.If the operand is false, the result is true.

Оператор поразрядного дополненияBitwise complement operator

Для операции в виде ~x, разрешение перегрузки унарного оператора (разрешение перегрузки унарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form ~x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Операнд преобразуется в тип параметра выбранного оператора и типом результата является тип возвращаемого значения оператора.The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. Ниже перечислены операторы предопределенные поразрядным дополнением значения.The predefined bitwise complement operators are:

int operator ~(int x);
uint operator ~(uint x);
long operator ~(long x);
ulong operator ~(ulong x);

Для каждого из этих операторов, результатом операции является побитовым дополнением x.For each of these operators, the result of the operation is the bitwise complement of x.

Каждый тип перечисления E неявно предоставляется следующий оператор поразрядного дополнения:Every enumeration type E implicitly provides the following bitwise complement operator:

E operator ~(E x);

Результат вычисления ~x, где x является выражением типа перечисления E с базовым типом U, именно так же, как оценка (E)(~(U)x), за исключением того, что преобразование в E — всегда выполняется в случае, если unchecked контекста (операторы checked и unchecked).The result of evaluating ~x, where x is an expression of an enumeration type E with an underlying type U, is exactly the same as evaluating (E)(~(U)x), except that the conversion to E is always performed as if in an unchecked context (The checked and unchecked operators).

Префиксные операторы инкремента и декрементаPrefix increment and decrement operators

pre_increment_expression
    : '++' unary_expression
    ;

pre_decrement_expression
    : '--' unary_expression
    ;

Операнд префикс инкремента или декремента операции должно быть выражением, классифицируется как переменная, доступ к свойству или индексатору.The operand of a prefix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. Результат операции является значение совпадает с типом операнда.The result of the operation is a value of the same type as the operand.

Если увеличить операнд префикса или декремента является свойство или индексатор, свойство или индексатор должны иметь get и set метода доступа.If the operand of a prefix increment or decrement operation is a property or indexer access, the property or indexer must have both a get and a set accessor. Если это не так, возникает ошибка времени привязки.If this is not the case, a binding-time error occurs.

Разрешение перегрузки унарного оператора (разрешение перегрузки унарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Предопределенные ++ и -- операторов существуют для следующих типов: sbyte, byte, short, ushort, int, uint, long, ulong, char , float, double, decimalи любой тип перечисления.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Предопределенный ++ операторы возвращают значение, полученное путем прибавления единицы к операнд и предварительно определенных -- операторы возвращают значение, полученное путем вычитания 1 из операнда.The predefined ++ operators return the value produced by adding 1 to the operand, and the predefined -- operators return the value produced by subtracting 1 from the operand. В checked контекста, если результат сложения или вычитания находится вне диапазона типа результата, а тип результата — целый тип или тип перечисления, System.OverflowException возникает исключение.In a checked context, if the result of this addition or subtraction is outside the range of the result type and the result type is an integral type or enum type, a System.OverflowException is thrown.

Во время выполнения обработки приращения префикс или операция формы декремента ++x или --x состоит из следующих действий:The run-time processing of a prefix increment or decrement operation of the form ++x or --x consists of the following steps:

  • Если x классифицируется как переменная:If x is classified as a variable:
    • x вычисляется для создания переменной.x is evaluated to produce the variable.
    • Выбранный оператор вызывается со значением x аргументом.The selected operator is invoked with the value of x as its argument.
    • Значение, возвращаемое оператором хранится в расположении, указанном при вычислении x.The value returned by the operator is stored in the location given by the evaluation of x.
    • Значение, возвращаемое оператором становится результатом операции.The value returned by the operator becomes the result of the operation.
  • Если x классифицируется как свойство или индексатор доступа:If x is classified as a property or indexer access:
    • Выражение экземпляра (если x не static) и список аргументов (если x имеет доступ к индексатору) связан x оцениваются, и полученные результаты используются в последующих get и set вызовы метода доступа.The instance expression (if x is not static) and the argument list (if x is an indexer access) associated with x are evaluated, and the results are used in the subsequent get and set accessor invocations.
    • get Метод доступа x вызывается.The get accessor of x is invoked.
    • Выбранный оператор вызывается с помощью значения, возвращенного get доступа в качестве аргумента.The selected operator is invoked with the value returned by the get accessor as its argument.
    • set Метод доступа x вызывается со значением, возвращенным оператором в качестве его value аргумент.The set accessor of x is invoked with the value returned by the operator as its value argument.
    • Значение, возвращаемое оператором становится результатом операции.The value returned by the operator becomes the result of the operation.

++ И -- операторы также поддерживают постфиксная нотация (постфиксных инкремента и декремента).The ++ and -- operators also support postfix notation (Postfix increment and decrement operators). Как правило, результат x++ или x-- является значением x до операции, тогда как результат ++x или --x является значением x после завершения операции.Typically, the result of x++ or x-- is the value of x before the operation, whereas the result of ++x or --x is the value of x after the operation. В любом случае x сам имеет то же значение после выполнения операции.In either case, x itself has the same value after the operation.

operator++ Или operator-- реализации можно вызывать в префиксной и постфиксной форме.An operator++ or operator-- implementation can be invoked using either postfix or prefix notation. Это не могут существовать разные реализации операторов для обозначения.It is not possible to have separate operator implementations for the two notations.

Выражения приведенияCast expressions

Объект cast_expression используется для явного преобразования выражения в заданный тип.A cast_expression is used to explicitly convert an expression to a given type.

cast_expression
    : '(' type ')' unary_expression
    ;

Объект cast_expression формы (T)E, где Tтип и Eunary_expression, выполняет явно преобразование (явные преобразования) значения E ввода T.A cast_expression of the form (T)E, where T is a type and E is a unary_expression, performs an explicit conversion (Explicit conversions) of the value of E to type T. Если существует явное преобразование из E для T, возникает ошибка во время привязки.If no explicit conversion exists from E to T, a binding-time error occurs. В противном случае результатом является значение, произведенное явное преобразование.Otherwise, the result is the value produced by the explicit conversion. Результат всегда классифицируется как значение, даже если E обозначает переменную.The result is always classified as a value, even if E denotes a variable.

Грамматика для cast_expression приводит к определенным синтаксической неоднозначности.The grammar for a cast_expression leads to certain syntactic ambiguities. Например, выражение (x)-y можно интерпретировать как cast_expression (приведение -y ввода x) или как additive_expression в сочетании с parenthesized_expression (который вычисляет значение x - y).For example, the expression (x)-y could either be interpreted as a cast_expression (a cast of -y to type x) or as an additive_expression combined with a parenthesized_expression (which computes the value x - y).

Чтобы устранить cast_expression существует неоднозначность, следующее правило: Последовательность из одного или нескольких маркераs (пробелы) заключены в круглые скобки, считается начала cast_expression только в том случае, если хотя бы одно из следующих условий:To resolve cast_expression ambiguities, the following rule exists: A sequence of one or more tokens (White space) enclosed in parentheses is considered the start of a cast_expression only if at least one of the following are true:

  • Последовательность лексем имеет правильную грамматику для тип, но не для выражение.The sequence of tokens is correct grammar for a type, but not for an expression.
  • Последовательность лексем имеет правильную грамматику для тип, и сразу после закрывающей круглой скобки маркер является маркером "~», маркер"!», маркер "(«, Идентификатор (последовательностей escape-символов Юникода), литерала (литералы), или любой ключевое слово(Ключевые слова) за исключением as и is.The sequence of tokens is correct grammar for a type, and the token immediately following the closing parentheses is the token "~", the token "!", the token "(", an identifier (Unicode character escape sequences), a literal (Literals), or any keyword (Keywords) except as and is.

Термин «правильную грамматику» выше означает только то, что последовательность токенов должны соответствовать конкретного грамматических производства.The term "correct grammar" above means only that the sequence of tokens must conform to the particular grammatical production. Он специально не учитывает фактическое значение все составные идентификаторы.It specifically does not consider the actual meaning of any constituent identifiers. Например если x и y являются идентификаторами, затем x.y имеет правильную грамматику для типа, даже если x.y фактически не указывает на тип.For example, if x and y are identifiers, then x.y is correct grammar for a type, even if x.y doesn't actually denote a type.

Из правила устранения неоднозначности следует, что если x и y являются идентификаторами, (x)y, (x)(y), и (x)(-y) являются cast_expressions, но (x)-y — нет, даже если x определяет тип.From the disambiguation rule it follows that, if x and y are identifiers, (x)y, (x)(y), and (x)(-y) are cast_expressions, but (x)-y is not, even if x identifies a type. Тем не менее если x является ключевым словом, идентифицирующим Предопределенный тип (такие как int), а затем все четыре формы являются cast_expressions (поскольку такое ключевое слово не может быть выражением само по себе).However, if x is a keyword that identifies a predefined type (such as int), then all four forms are cast_expressions (because such a keyword could not possibly be an expression by itself).

Выражения awaitAwait expressions

Оператор await используется для приостановки вычислений, включающей функции async до завершения асинхронной операции, представленное операндом.The await operator is used to suspend evaluation of the enclosing async function until the asynchronous operation represented by the operand has completed.

await_expression
    : 'await' unary_expression
    ;

Await_expression допускается только в теле функции async (итераторы).An await_expression is only allowed in the body of an async function (Iterators). В ближайшем вложенном асинхронной функции await_expression не может указываться в этих местах:Within the nearest enclosing async function, an await_expression may not occur in these places:

  • Анонимные функции вложенные (синхронные)Inside a nested (non-async) anonymous function
  • Внутри блока lock_statementInside the block of a lock_statement
  • В небезопасном контексте.In an unsafe context

Обратите внимание, что await_expression не может использоваться в большинстве мест в query_expression, так как их синтаксически преобразуются использовать синхронные лямбда-выражения.Note that an await_expression cannot occur in most places within a query_expression, because those are syntactically transformed to use non-async lambda expressions.

В функцию с модификатором async await нельзя использовать в качестве идентификатора.Inside of an async function, await cannot be used as an identifier. Таким образом является не синтаксической неоднозначности между await выражения и различных выражений, содержащих идентификаторы.There is therefore no syntactic ambiguity between await-expressions and various expressions involving identifiers. За пределами асинхронные функции await выступает в качестве обычного идентификатора.Outside of async functions, await acts as a normal identifier.

Операнд await_expression называется задачи.The operand of an await_expression is called the task. Он представляет асинхронную операцию, которая может быть не завершено во время await_expression вычисляется.It represents an asynchronous operation that may or may not be complete at the time the await_expression is evaluated. Оператор await предназначена для приостановки выполнения включающей функции async, пока не будет завершена ожидаемая задача, а затем получать его результат.The purpose of the await operator is to suspend execution of the enclosing async function until the awaited task is complete, and then obtain its outcome.

Awaitable выраженияAwaitable expressions

Задача выражения await должен быть awaitable.The task of an await expression is required to be awaitable. Выражение t несинхронизируемый, если справедливо одно из следующих условий:An expression t is awaitable if one of the following holds:

  • t имеет тип времени компиляции dynamict is of compile time type dynamic
  • t имеет доступный метод экземпляра или расширения вызывается GetAwaiter без параметров и без параметров типа и типом возвращаемого значения A для которого все указанные ниже хранения:t has an accessible instance or extension method called GetAwaiter with no parameters and no type parameters, and a return type A for which all of the following hold:
    • A реализует интерфейс System.Runtime.CompilerServices.INotifyCompletion (Далее — INotifyCompletion для краткости)A implements the interface System.Runtime.CompilerServices.INotifyCompletion (hereafter known as INotifyCompletion for brevity)
    • A имеет свойство доступным для чтения экземпляр IsCompleted типа boolA has an accessible, readable instance property IsCompleted of type bool
    • A имеет доступным методом экземпляра GetResult без параметров и без параметров типаA has an accessible instance method GetResult with no parameters and no type parameters

Цель GetAwaiter метод должен получать awaiter для задачи.The purpose of the GetAwaiter method is to obtain an awaiter for the task. Тип A называется типа awaiter для выражения await.The type A is called the awaiter type for the await expression.

Цель IsCompleted свойство является определение того, если задача уже завершена.The purpose of the IsCompleted property is to determine if the task is already complete. Если Да, нет необходимости для приостановки вычислений.If so, there is no need to suspend evaluation.

Цель INotifyCompletion.OnCompleted метод — зарегистрироваться «продолжение» для задачи; т. е. делегат (типа System.Action), будет вызываться после завершения задачи.The purpose of the INotifyCompletion.OnCompleted method is to sign up a "continuation" to the task; i.e. a delegate (of type System.Action) that will be invoked once the task is complete.

Цель GetResult является метод получения результата задачи, после его завершения.The purpose of the GetResult method is to obtain the outcome of the task once it is complete. Этот результат может быть завершен успешно, возможно, с результирующее значение, или может быть исключение, которое вызывается GetResult метод.This outcome may be successful completion, possibly with a result value, or it may be an exception which is thrown by the GetResult method.

Классификация выражениях awaitClassification of await expressions

Выражение await t классифицируется так же, как выражение (t).GetAwaiter().GetResult().The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). Таким образом Если тип возвращаемого значения GetResultvoid, await_expression классифицируется как nothing.Thus, if the return type of GetResult is void, the await_expression is classified as nothing. Если он имеет тип возврата, отличный от void T, await_expression классифицируется как значение типа T.If it has a non-void return type T, the await_expression is classified as a value of type T.

Выражения await вычисления среды выполненияRuntime evaluation of await expressions

Во время выполнения выражение await t вычисляется следующим образом:At runtime, the expression await t is evaluated as follows:

  • Объект типа awaiter a получается путем вычисления выражения (t).GetAwaiter().An awaiter a is obtained by evaluating the expression (t).GetAwaiter().
  • Объект bool b получается путем вычисления выражения (a).IsCompleted.A bool b is obtained by evaluating the expression (a).IsCompleted.
  • Если bfalse то оценки зависит от того a реализует интерфейс System.Runtime.CompilerServices.ICriticalNotifyCompletion (Далее — ICriticalNotifyCompletion для краткости).If b is false then evaluation depends on whether a implements the interface System.Runtime.CompilerServices.ICriticalNotifyCompletion (hereafter known as ICriticalNotifyCompletion for brevity). Эта проверка выполняется при привязке; т. е. во время выполнения при a имеет тип времени компиляции dynamicи во время компиляции в противном случае.This check is done at binding time; i.e. at runtime if a has the compile time type dynamic, and at compile time otherwise. Позвольте r обозначения возобновления делегат (итераторы):Let r denote the resumption delegate (Iterators):
    • Если a не реализует ICriticalNotifyCompletion, то результатом выражения (a as (INotifyCompletion)).OnCompleted(r) вычисляется.If a does not implement ICriticalNotifyCompletion, then the expression (a as (INotifyCompletion)).OnCompleted(r) is evaluated.
    • Если a реализовать ICriticalNotifyCompletion, то результатом выражения (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r) вычисляется.If a does implement ICriticalNotifyCompletion, then the expression (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r) is evaluated.
    • Оценки затем приостанавливается и управление возвращается вызывающему объекту текущего асинхронной функции.Evaluation is then suspended, and control is returned to the current caller of the async function.
  • Либо сразу же после (если b был true), или после последующего вызова делегата возобновления (если b был false), выражение (a).GetResult() вычисляется.Either immediately after (if b was true), or upon later invocation of the resumption delegate (if b was false), the expression (a).GetResult() is evaluated. Если он возвращает значение, это значение является результатом await_expression.If it returns a value, that value is the result of the await_expression. В противном случае результатом будет ничего.Otherwise the result is nothing.

Объект типа awaiter реализации методов интерфейса INotifyCompletion.OnCompleted и ICriticalNotifyCompletion.UnsafeOnCompleted должна вызывать делегат r вызываемого не более одного раза.An awaiter's implementation of the interface methods INotifyCompletion.OnCompleted and ICriticalNotifyCompletion.UnsafeOnCompleted should cause the delegate r to be invoked at most once. В противном случае поведение включающей функции async не определено.Otherwise, the behavior of the enclosing async function is undefined.

Арифметические операторыArithmetic operators

*, /, %, +, И - называются арифметические операторы.The *, /, %, +, and - operators are called the arithmetic operators.

multiplicative_expression
    : unary_expression
    | multiplicative_expression '*' unary_expression
    | multiplicative_expression '/' unary_expression
    | multiplicative_expression '%' unary_expression
    ;

additive_expression
    : multiplicative_expression
    | additive_expression '+' multiplicative_expression
    | additive_expression '-' multiplicative_expression
    ;

Если операнд арифметический оператор имеет тип времени компиляции dynamic, а затем он динамически связан (динамической привязки).If an operand of an arithmetic operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). В данном случае является типов во время компиляции выражения dynamic, а разрешение, приведенное ниже будет иметь место во время выполнения, используя тип времени выполнения операндов, имеющих указанный тип времени компиляции dynamic.In this case the compile-time type of the expression is dynamic, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic.

Оператор умноженияMultiplication operator

Для операции в виде x * y, разрешение перегрузки бинарного оператора (разрешить перегрузку бинарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form x * y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Операнды преобразуются в типы параметров выбранного оператора и типом результата является тип возвращаемого значения оператора.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Ниже перечислены стандартные операторы произведения.The predefined multiplication operators are listed below. Все операторы вычислить произведение x и y.The operators all compute the product of x and y.

  • Произведение целых чисел:Integer multiplication:

    int operator *(int x, int y);
    uint operator *(uint x, uint y);
    long operator *(long x, long y);
    ulong operator *(ulong x, ulong y);
    

    В checked контекста, если продукт за пределами диапазона типа результата, System.OverflowException возникает исключение.In a checked context, if the product is outside the range of the result type, a System.OverflowException is thrown. В unchecked контекст, переполнение не выводятся и удаляются любые существенные старшие разряды вне диапазона типа результата.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Умножения с плавающей запятой:Floating-point multiplication:

    float operator *(float x, float y);
    double operator *(double x, double y);
    

    Произведение вычисляется в соответствии с правилами стандарта IEEE 754 арифметические.The product is computed according to the rules of IEEE 754 arithmetic. Ниже перечислены все возможные сочетания ненулевых значений ограниченная, нули, бесконечностей и NaN результаты.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. В таблице x и y являются положительными значениями.In the table, x and y are positive finite values. z является результатом x * y.z is the result of x * y. Если результат слишком велик для целевого типа, z равно бесконечности.If the result is too large for the destination type, z is infinity. Если результат слишком мал для целевого типа, z равно нулю.If the result is too small for the destination type, z is zero.

    + y+y -y-y +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    +x+x + z+z -z-z +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    -x-x -z-z + z+z -0-0 +0+0 -inf-inf +inf+inf NaNNaN
    +0+0 +0+0 -0-0 +0+0 -0-0 NaNNaN NaNNaN NaNNaN
    -0-0 -0-0 +0+0 -0-0 +0+0 NaNNaN NaNNaN NaNNaN
    +inf+inf +inf+inf -inf-inf NaNNaN NaNNaN +inf+inf -inf-inf NaNNaN
    -inf-inf -inf-inf +inf+inf NaNNaN NaNNaN -inf-inf +inf+inf NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Произведение десятичных чисел.Decimal multiplication:

    decimal operator *(decimal x, decimal y);
    

    Если полученное значение слишком велико для представления в decimal формат, System.OverflowException возникает исключение.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Если результат слишком мал для представления в decimal формате, результат равен нулю.If the result value is too small to represent in the decimal format, the result is zero. Масштаб результата, до округления равно сумме шкал двух операндов.The scale of the result, before any rounding, is the sum of the scales of the two operands.

    Равнозначно использованию оператор умножения типа Decimal умножения System.Decimal.Decimal multiplication is equivalent to using the multiplication operator of type System.Decimal.

Оператор деленияDivision operator

Для операции в виде x / y, разрешение перегрузки бинарного оператора (разрешить перегрузку бинарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form x / y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Операнды преобразуются в типы параметров выбранного оператора и типом результата является тип возвращаемого значения оператора.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Ниже перечислены стандартные операторы деления.The predefined division operators are listed below. Все операторы вычисляют частное x и y.The operators all compute the quotient of x and y.

  • Деление целых чисел:Integer division:

    int operator /(int x, int y);
    uint operator /(uint x, uint y);
    long operator /(long x, long y);
    ulong operator /(ulong x, ulong y);
    

    Если значение правый операнд равен нулю, System.DivideByZeroException возникает исключение.If the value of the right operand is zero, a System.DivideByZeroException is thrown.

    Деление округляет результат в сторону нуля.The division rounds the result towards zero. Таким образом абсолютное значение результата является наибольшее целое число, меньше или равно абсолютному значению частного двух операндов.Thus the absolute value of the result is the largest possible integer that is less than or equal to the absolute value of the quotient of the two operands. Результатом будет нуль или положительное число, если два операнда имеют тот же знак и ноль или отрицательное значение, если два операнда имеют противоположные знаки.The result is zero or positive when the two operands have the same sign and zero or negative when the two operands have opposite signs.

    Если левый операнд является наименьшим представимым int или long значение и правый операнд является -1, возникает переполнение.If the left operand is the smallest representable int or long value and the right operand is -1, an overflow occurs. В checked контекст, в результате System.ArithmeticException (или его подкласс) исключение.In a checked context, this causes a System.ArithmeticException (or a subclass thereof) to be thrown. В unchecked контекста, он определяется реализацией указатель, является ли System.ArithmeticException (или его подкласс) возникает исключение или недокументированных этим значением, что левого операнда.In an unchecked context, it is implementation-defined as to whether a System.ArithmeticException (or a subclass thereof) is thrown or the overflow goes unreported with the resulting value being that of the left operand.

  • Деление с плавающей запятой:Floating-point division:

    float operator /(float x, float y);
    double operator /(double x, double y);
    

    Частное вычисляется в соответствии с правилами стандарта IEEE 754 арифметические.The quotient is computed according to the rules of IEEE 754 arithmetic. Ниже перечислены все возможные сочетания ненулевых значений ограниченная, нули, бесконечностей и NaN результаты.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. В таблице x и y являются положительными значениями.In the table, x and y are positive finite values. z является результатом x / y.z is the result of x / y. Если результат слишком велик для целевого типа, z равно бесконечности.If the result is too large for the destination type, z is infinity. Если результат слишком мал для целевого типа, z равно нулю.If the result is too small for the destination type, z is zero.

    + y+y -y-y +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    +x+x + z+z -z-z +inf+inf -inf-inf +0+0 -0-0 NaNNaN
    -x-x -z-z + z+z -inf-inf +inf+inf -0-0 +0+0 NaNNaN
    +0+0 +0+0 -0-0 NaNNaN NaNNaN +0+0 -0-0 NaNNaN
    -0-0 -0-0 +0+0 NaNNaN NaNNaN -0-0 +0+0 NaNNaN
    +inf+inf +inf+inf -inf-inf +inf+inf -inf-inf NaNNaN NaNNaN NaNNaN
    -inf-inf -inf-inf +inf+inf -inf-inf +inf+inf NaNNaN NaNNaN NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Деление десятичных чисел:Decimal division:

    decimal operator /(decimal x, decimal y);
    

    Если значение правый операнд равен нулю, System.DivideByZeroException возникает исключение.If the value of the right operand is zero, a System.DivideByZeroException is thrown. Если полученное значение слишком велико для представления в decimal формат, System.OverflowException возникает исключение.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Если результат слишком мал для представления в decimal формате, результат равен нулю.If the result value is too small to represent in the decimal format, the result is zero. Масштаб результата является наименьшим шкалы, сохранит результат равен ближайшему представимым десятичное значение для true математический результат.The scale of the result is the smallest scale that will preserve a result equal to the nearest representable decimal value to the true mathematical result.

    Деление десятичных чисел эквивалентно использованию оператора деления типа System.Decimal.Decimal division is equivalent to using the division operator of type System.Decimal.

Оператор остаткаRemainder operator

Для операции в виде x % y, разрешение перегрузки бинарного оператора (разрешить перегрузку бинарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form x % y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Операнды преобразуются в типы параметров выбранного оператора и типом результата является тип возвращаемого значения оператора.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Ниже перечислены стандартные операторы остатка.The predefined remainder operators are listed below. Все операторы вычисления остатка от деления x и y.The operators all compute the remainder of the division between x and y.

  • Целочисленный остаток:Integer remainder:

    int operator %(int x, int y);
    uint operator %(uint x, uint y);
    long operator %(long x, long y);
    ulong operator %(ulong x, ulong y);
    

    Результат x % y является значение, полученное путем x - (x / y) * y.The result of x % y is the value produced by x - (x / y) * y. Если y равен нулю, System.DivideByZeroException возникает исключение.If y is zero, a System.DivideByZeroException is thrown.

    Если левый операнд — наименьшей int или long значение и правый операнд является -1, System.OverflowException возникает исключение.If the left operand is the smallest int or long value and the right operand is -1, a System.OverflowException is thrown. В любом случае выполняет x % y создания исключения, где x / y не вызовет исключение.In no case does x % y throw an exception where x / y would not throw an exception.

  • Остаток с плавающей запятой:Floating-point remainder:

    float operator %(float x, float y);
    double operator %(double x, double y);
    

    Ниже перечислены все возможные сочетания ненулевых значений ограниченная, нули, бесконечностей и NaN результаты.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. В таблице x и y являются положительными значениями.In the table, x and y are positive finite values. z является результатом x % y и вычисляется как x - n * y, где n наибольшее возможных целое число, которое меньше или равно x / y.z is the result of x % y and is computed as x - n * y, where n is the largest possible integer that is less than or equal to x / y. Этот метод вычисления остатка аналогично тому, который использовался для целочисленных операнда, но отличается от определения IEEE 754 (в котором n — целое число, ближайшее к x / y).This method of computing the remainder is analogous to that used for integer operands, but differs from the IEEE 754 definition (in which n is the integer closest to x / y).

    + y+y -y-y +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    +x+x + z+z + z+z NaNNaN NaNNaN xx xx NaNNaN
    -x-x -z-z -z-z NaNNaN NaNNaN -x-x -x-x NaNNaN
    +0+0 +0+0 +0+0 NaNNaN NaNNaN +0+0 +0+0 NaNNaN
    -0-0 -0-0 -0-0 NaNNaN NaNNaN -0-0 -0-0 NaNNaN
    +inf+inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
    -inf-inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Остаток для десятичных чисел:Decimal remainder:

    decimal operator %(decimal x, decimal y);
    

    Если значение правый операнд равен нулю, System.DivideByZeroException возникает исключение.If the value of the right operand is zero, a System.DivideByZeroException is thrown. Масштаб результата, до округления равен большему из масштабов двух операндов, а знак результата, если ненулевое значение, является таким же, как x.The scale of the result, before any rounding, is the larger of the scales of the two operands, and the sign of the result, if non-zero, is the same as that of x.

    Равнозначно использованию оператора вычисления остатка типа Decimal остаток System.Decimal.Decimal remainder is equivalent to using the remainder operator of type System.Decimal.

Оператор сложенияAddition operator

Для операции в виде x + y, разрешение перегрузки бинарного оператора (разрешить перегрузку бинарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form x + y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Операнды преобразуются в типы параметров выбранного оператора и типом результата является тип возвращаемого значения оператора.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Ниже перечислены стандартные операторы сложения.The predefined addition operators are listed below. Для числовые типы и типы перечисления стандартные операторы сложения вычисляет сумму двух операндов.For numeric and enumeration types, the predefined addition operators compute the sum of the two operands. Если один или оба операнда имеют строковый тип, стандартные операторы сложения СЦЕПИТЬ строковым представлением операндов.When one or both operands are of type string, the predefined addition operators concatenate the string representation of the operands.

  • Сложение целых чисел:Integer addition:

    int operator +(int x, int y);
    uint operator +(uint x, uint y);
    long operator +(long x, long y);
    ulong operator +(ulong x, ulong y);
    

    В checked контекста, если сумма находится вне диапазона типа результата, System.OverflowException возникает исключение.In a checked context, if the sum is outside the range of the result type, a System.OverflowException is thrown. В unchecked контекст, переполнение не выводятся и удаляются любые существенные старшие разряды вне диапазона типа результата.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Сложение чисел с плавающей запятой:Floating-point addition:

    float operator +(float x, float y);
    double operator +(double x, double y);
    

    Сумма вычисляется в соответствии с правилами стандарта IEEE 754 арифметические.The sum is computed according to the rules of IEEE 754 arithmetic. Ниже перечислены все возможные сочетания ненулевых значений ограниченная, нули, бесконечностей и NaN результаты.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. В таблице x и y являются ненулевыми значениями конечное, и z является результатом x + y.In the table, x and y are nonzero finite values, and z is the result of x + y. Если x и y имеют одинаковую величину, но противоположные знаки, z -положительный ноль.If x and y have the same magnitude but opposite signs, z is positive zero. Если x + y слишком велико для представления в целевом типе, z является бесконечным с тот же знак, что x + y.If x + y is too large to represent in the destination type, z is an infinity with the same sign as x + y.

    yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    xx зz xx xx +inf+inf -inf-inf NaNNaN
    +0+0 yy +0+0 +0+0 +inf+inf -inf-inf NaNNaN
    -0-0 yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    +inf+inf +inf+inf +inf+inf +inf+inf +inf+inf NaNNaN NaNNaN
    -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN -inf-inf NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Сложение десятичных чисел:Decimal addition:

    decimal operator +(decimal x, decimal y);
    

    Если полученное значение слишком велико для представления в decimal формат, System.OverflowException возникает исключение.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Масштаб результата, до округления равен большему из масштабов двух операндов.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    Decimal эквивалентно использование оператора сложения типа System.Decimal.Decimal addition is equivalent to using the addition operator of type System.Decimal.

  • Помимо этого перечисления.Enumeration addition. Каждый тип перечисления неявно предоставляет следующие предварительно определенные операторы, где E является типом перечисления и U является базовым типом объекта E:Every enumeration type implicitly provides the following predefined operators, where E is the enum type, and U is the underlying type of E:

    E operator +(E x, U y);
    E operator +(U x, E y);
    

    Во время выполнения эти операторы выполняются точно так, как (E)((U)x + (U)y).At run-time these operators are evaluated exactly as (E)((U)x + (U)y).

  • Объединение строк:String concatenation:

    string operator +(string x, string y);
    string operator +(string x, object y);
    string operator +(object x, string y);
    

    Эти перегрузки двоичного файла + оператор выполняют объединение строк.These overloads of the binary + operator perform string concatenation. Если операнд операции объединения строк null, подставляется пустой строкой.If an operand of string concatenation is null, an empty string is substituted. В противном случае любой аргумент нестроковых преобразуется в строковое представление путем вызова виртуального ToString метод наследуется от типа object.Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. Если ToString возвращает null, подставляется пустой строкой.If ToString returns null, an empty string is substituted.

    using System;
    
    class Test
    {
        static void Main() {
            string s = null;
            Console.WriteLine("s = >" + s + "<");        // displays s = ><
            int i = 1;
            Console.WriteLine("i = " + i);               // displays i = 1
            float f = 1.2300E+15F;
            Console.WriteLine("f = " + f);               // displays f = 1.23E+15
            decimal d = 2.900m;
            Console.WriteLine("d = " + d);               // displays d = 2.900
        }
    }
    

    Результат оператора объединения строк является строка, состоящая из символов левого операнда следуют символы правого операнда. Оператор объединения строк никогда не возвращает null значение. Объект System.OutOfMemoryException может быть вызвано, если не хватает памяти для выделения результирующая строка.A System.OutOfMemoryException may be thrown if there is not enough memory available to allocate the resulting string.

  • Объединению делегатов.Delegate combination. Каждый тип делегата неявно предоставляется следующий стандартный оператор, где D является типом делегата:Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator +(D x, D y);
    

    Двоичный файл + оператор выполняет объединение делегатов, когда оба операнда имеют некоторый тип делегата D.The binary + operator performs delegate combination when both operands are of some delegate type D. (Если операнды имеют разные типы делегатов, происходит ошибка времени привязки.) Если первый операнд имеет null, результатом операции является значение второго операнда (даже если это также null).(If the operands have different delegate types, a binding-time error occurs.) If the first operand is null, the result of the operation is the value of the second operand (even if that is also null). В противном случае, если второй операнд является null, то результатом операции является значение первого операнда.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. В противном случае результатом операции является новый экземпляр делегата, который, при вызове, вызывает первый операнд и затем вызывает второго операнда.Otherwise, the result of the operation is a new delegate instance that, when invoked, invokes the first operand and then invokes the second operand. Примеры объединение делегатов, см. в разделе оператор вычитания и вызов делегата.For examples of delegate combination, see Subtraction operator and Delegate invocation. Так как System.Delegate не является типом делегата operator  + для него не определен.Since System.Delegate is not a delegate type, operator + is not defined for it.

Оператор вычитанияSubtraction operator

Для операции в виде x - y, разрешение перегрузки бинарного оператора (разрешить перегрузку бинарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form x - y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Операнды преобразуются в типы параметров выбранного оператора и типом результата является тип возвращаемого значения оператора.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Ниже перечислены стандартные операторы вычитания.The predefined subtraction operators are listed below. Операторы, все вычесть y из x.The operators all subtract y from x.

  • Вычитание целых чисел:Integer subtraction:

    int operator -(int x, int y);
    uint operator -(uint x, uint y);
    long operator -(long x, long y);
    ulong operator -(ulong x, ulong y);
    

    В checked контекста, если разница находится вне диапазона типа результата, System.OverflowException возникает исключение.In a checked context, if the difference is outside the range of the result type, a System.OverflowException is thrown. В unchecked контекст, переполнение не выводятся и удаляются любые существенные старшие разряды вне диапазона типа результата.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Вычитания с плавающей запятой:Floating-point subtraction:

    float operator -(float x, float y);
    double operator -(double x, double y);
    

    Разность вычисляется в соответствии с правилами стандарта IEEE 754 арифметические.The difference is computed according to the rules of IEEE 754 arithmetic. Ниже перечислены результаты всех возможных сочетаний ненулевых значений ограниченная, нули, бесконечности и значения NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaNs. В таблице x и y являются ненулевыми значениями конечное, и z является результатом x - y.In the table, x and y are nonzero finite values, and z is the result of x - y. Если x и y равны, z -положительный ноль.If x and y are equal, z is positive zero. Если x - y слишком велико для представления в целевом типе, z является бесконечным с тот же знак, что x - y.If x - y is too large to represent in the destination type, z is an infinity with the same sign as x - y.

    yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    xx зz xx xx -inf-inf +inf+inf NaNNaN
    +0+0 -y-y +0+0 +0+0 -inf-inf +inf+inf NaNNaN
    -0-0 -y-y -0-0 +0+0 -inf-inf +inf+inf NaNNaN
    +inf+inf +inf+inf +inf+inf +inf+inf NaNNaN +inf+inf NaNNaN
    -inf-inf -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Вычитание десятичных чисел.Decimal subtraction:

    decimal operator -(decimal x, decimal y);
    

    Если полученное значение слишком велико для представления в decimal формат, System.OverflowException возникает исключение.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Масштаб результата, до округления равен большему из масштабов двух операндов.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    Вычитание десятичных чисел эквивалентно использованию оператора вычитания типа System.Decimal.Decimal subtraction is equivalent to using the subtraction operator of type System.Decimal.

  • Вычитание перечисления.Enumeration subtraction. Каждый тип перечисления неявно предоставляется следующий стандартный оператор, где E является типом перечисления и U является базовым типом объекта E:Every enumeration type implicitly provides the following predefined operator, where E is the enum type, and U is the underlying type of E:

    U operator -(E x, E y);
    

    Этот оператор выполняется точно так, как (U)((U)x - (U)y).This operator is evaluated exactly as (U)((U)x - (U)y). Другими словами, оператор вычисляет разницу между порядковыми значениями x и y, а тип результата — базовый тип перечисления.In other words, the operator computes the difference between the ordinal values of x and y, and the type of the result is the underlying type of the enumeration.

    E operator -(E x, U y);
    

    Этот оператор выполняется точно так, как (E)((U)x - y).This operator is evaluated exactly as (E)((U)x - y). Другими словами оператор вычитает значение из базового типа перечисления, выдавая значение перечисления.In other words, the operator subtracts a value from the underlying type of the enumeration, yielding a value of the enumeration.

  • Удаление делегатов.Delegate removal. Каждый тип делегата неявно предоставляется следующий стандартный оператор, где D является типом делегата:Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator -(D x, D y);
    

    Двоичный файл - оператор выполняет удаление делегатов, когда оба операнда имеют некоторый тип делегата D.The binary - operator performs delegate removal when both operands are of some delegate type D. Если операнды имеют разные типы делегатов, возникает ошибка времени привязки.If the operands have different delegate types, a binding-time error occurs. Если первый операнд имеет null, результатом операции является null.If the first operand is null, the result of the operation is null. В противном случае, если второй операнд является null, то результатом операции является значение первого операнда.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. В противном случае оба операнда представляют списки вызовов (объявления делегатов) наличие одной или несколькими записями, а результат является новый список вызовов, состоящая из первого операнда со второго операнда элементов, удаленных из предоставленный список второго операнда это правильное смежных подсписок первого элемента.Otherwise, both operands represent invocation lists (Delegate declarations) having one or more entries, and the result is a new invocation list consisting of the first operand's list with the second operand's entries removed from it, provided the second operand's list is a proper contiguous sublist of the first's. (Для определения равенства подсписка, сравнение соответствующих записей, как и для оператора равенства делегатов (делегировать операторы равенства).) В противном случае результатом является значение левого операнда.(To determine sublist equality, corresponding entries are compared as for the delegate equality operator (Delegate equality operators).) Otherwise, the result is the value of the left operand. Ни один из операндов списки изменяется в процессе.Neither of the operands' lists is changed in the process. Если список второго операнда соответствует несколько подсписка последовательных записей в списке первого операнда, крайнего правого сопоставления подсписок последовательных записей удаляется.If the second operand's list matches multiple sublists of contiguous entries in the first operand's list, the right-most matching sublist of contiguous entries is removed. Если для удаления получается пустой список, возвращается null.If removal results in an empty list, the result is null. Пример:For example:

    delegate void D(int x);
    
    class C
    {
        public static void M1(int i) { /* ... */ }
        public static void M2(int i) { /* ... */ }
    }
    
    class Test
    {
        static void Main() { 
            D cd1 = new D(C.M1);
            D cd2 = new D(C.M2);
            D cd3 = cd1 + cd2 + cd2 + cd1;   // M1 + M2 + M2 + M1
            cd3 -= cd1;                      // => M1 + M2 + M2
    
            cd3 = cd1 + cd2 + cd2 + cd1;     // M1 + M2 + M2 + M1
            cd3 -= cd1 + cd2;                // => M2 + M1
    
            cd3 = cd1 + cd2 + cd2 + cd1;     // M1 + M2 + M2 + M1
            cd3 -= cd2 + cd2;                // => M1 + M1
    
            cd3 = cd1 + cd2 + cd2 + cd1;     // M1 + M2 + M2 + M1
            cd3 -= cd2 + cd1;                // => M1 + M2
    
            cd3 = cd1 + cd2 + cd2 + cd1;     // M1 + M2 + M2 + M1
            cd3 -= cd1 + cd1;                // => M1 + M2 + M2 + M1
        }
    }
    

Операторы сдвигаShift operators

<< И >> операторы используются для выполнения операции сдвига разрядов.The << and >> operators are used to perform bit shifting operations.

shift_expression
    : additive_expression
    | shift_expression '<<' additive_expression
    | shift_expression right_shift additive_expression
    ;

Если операнд shift_expression имеет тип времени компиляции dynamic, а затем он динамически связан (динамической привязки).If an operand of a shift_expression has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). В данном случае является типов во время компиляции выражения dynamic, а разрешение, приведенное ниже будет иметь место во время выполнения, используя тип времени выполнения операндов, имеющих указанный тип времени компиляции dynamic.In this case the compile-time type of the expression is dynamic, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic.

Для операции в виде x << count или x >> count, разрешение перегрузки бинарного оператора (разрешить перегрузку бинарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form x << count or x >> count, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Операнды преобразуются в типы параметров выбранного оператора и типом результата является тип возвращаемого значения оператора.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

При объявлении перегруженного оператора сдвига, тип первого операнда всегда должен быть класс или структура, содержащая объявление оператора, а тип второго операнда должен всегда быть int.When declaring an overloaded shift operator, the type of the first operand must always be the class or struct containing the operator declaration, and the type of the second operand must always be int.

Предопределенные операторы перечислены ниже.The predefined shift operators are listed below.

  • Сдвиг влево:Shift left:

    int operator <<(int x, int count);
    uint operator <<(uint x, int count);
    long operator <<(long x, int count);
    ulong operator <<(ulong x, int count);
    

    << Смены оператор x влево на количество битов, которое вычисляется, как описано ниже.The << operator shifts x left by a number of bits computed as described below.

    Старшие разряды вне диапазона типа результата x будут удалены, а оставшиеся биты сдвигаются влево и позиции битов пустые младшие присваивается нулевое значение.The high-order bits outside the range of the result type of x are discarded, the remaining bits are shifted left, and the low-order empty bit positions are set to zero.

  • Сдвиг вправо:Shift right:

    int operator >>(int x, int count);
    uint operator >>(uint x, int count);
    long operator >>(long x, int count);
    ulong operator >>(ulong x, int count);
    

    >> Смены оператор x вправо на количество битов, которое вычисляется, как описано ниже.The >> operator shifts x right by a number of bits computed as described below.

    Когда x имеет тип int или long, младшие биты x , удален, а оставшиеся биты сдвигаются вправо и позиции пустой бит высокого порядка устанавливаются в нуль, если x неотрицательное он имеет значение, если один x является отрицательным.When x is of type int or long, the low-order bits of x are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero if x is non-negative and set to one if x is negative.

    Когда x имеет тип uint или ulong, младшие биты x будут удалены, а оставшиеся биты сдвигаются вправо, и пустой бит высокого порядка позиций присваивается нулевое значение.When x is of type uint or ulong, the low-order bits of x are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero.

Для стандартных операторов количество битов для сдвига вычисляется следующим образом:For the predefined operators, the number of bits to shift is computed as follows:

  • Если тип xint или uint, величина сдвига определяется пятью младшими разрядами из count.When the type of x is int or uint, the shift count is given by the low-order five bits of count. Другими словами, величина сдвига вычисляется на основе count & 0x1F.In other words, the shift count is computed from count & 0x1F.
  • Если тип xlong или ulong, величина сдвига определяется шестью младшими разрядами из count.When the type of x is long or ulong, the shift count is given by the low-order six bits of count. Другими словами, величина сдвига вычисляется на основе count & 0x3F.In other words, the shift count is computed from count & 0x3F.

Если счетчик принял shift равно нулю, операторы сдвига просто возвращают значение x.If the resulting shift count is zero, the shift operators simply return the value of x.

Операции сдвига никогда не вызывают переполнение и дают одинаковые результаты в checked и unchecked контекстов.Shift operations never cause overflows and produce the same results in checked and unchecked contexts.

Если левый операнд >> оператор имеет целочисленный тип со знаком, оператор выполняет арифметический сдвиг вправо при котором значение значащий бит (бит знака) операнда распространяется на позиции пустой бит высокого порядка.When the left operand of the >> operator is of a signed integral type, the operator performs an arithmetic shift right wherein the value of the most significant bit (the sign bit) of the operand is propagated to the high-order empty bit positions. Если левый операнд >> оператор имеет целочисленный тип без знака, оператор выполняет логическим сдвигом вправо при котором позиции пустой битов высокого порядка всегда присваивается нулевое значение.When the left operand of the >> operator is of an unsigned integral type, the operator performs a logical shift right wherein high-order empty bit positions are always set to zero. Для выполнения обратной операции выводится из типа операнда, можно использовать явные приведения.To perform the opposite operation of that inferred from the operand type, explicit casts can be used. Например если x является переменной типа int, операция unchecked((int)((uint)x >> y)) выполняет логическим сдвигом справа от x.For example, if x is a variable of type int, the operation unchecked((int)((uint)x >> y)) performs a logical shift right of x.

Относительные операторы и операторы тестирования типаRelational and type-testing operators

==, !=, <, >, <=, >=, is И as называются операторами отношения и проверки типа.The ==, !=, <, >, <=, >=, is and as operators are called the relational and type-testing operators.

relational_expression
    : shift_expression
    | relational_expression '<' shift_expression
    | relational_expression '>' shift_expression
    | relational_expression '<=' shift_expression
    | relational_expression '>=' shift_expression
    | relational_expression 'is' type
    | relational_expression 'as' type
    ;

equality_expression
    : relational_expression
    | equality_expression '==' relational_expression
    | equality_expression '!=' relational_expression
    ;

is Разделе является оператором и as разделе оператор As.The is operator is described in The is operator and the as operator is described in The as operator.

==, !=, <, >, <= И >= операторы операторы сравнения.The ==, !=, <, >, <= and >= operators are comparison operators.

Если операнд оператора сравнения имеет тип времени компиляции dynamic, а затем он динамически связан (динамической привязки).If an operand of a comparison operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). В данном случае является типов во время компиляции выражения dynamic, а разрешение, приведенное ниже будет иметь место во время выполнения, используя тип времени выполнения операндов, имеющих указанный тип времени компиляции dynamic.In this case the compile-time type of the expression is dynamic, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic.

Для операции в виде x op y, где op является оператором сравнения, разрешение перегрузки (Разрешитьперегрузкубинарногооператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form x op y, where op is a comparison operator, overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Операнды преобразуются в типы параметров выбранного оператора и типом результата является тип возвращаемого значения оператора.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Стандартные операторы сравнения описаны в следующих разделах.The predefined comparison operators are described in the following sections. Все стандартные операторы сравнения возвращают результат типа bool, как описано в следующей таблице.All predefined comparison operators return a result of type bool, as described in the following table.

ОперацияOperation РезультатResult
x == y true Если x равен y, false в противном случаеtrue if x is equal to y, false otherwise
x != y true Если x не равно y, false в противном случаеtrue if x is not equal to y, false otherwise
x < y true Если x — меньше, чем y, false в противном случаеtrue if x is less than y, false otherwise
x > y true Если x больше, чем y, false в противном случаеtrue if x is greater than y, false otherwise
x <= y true Если x меньше или равно y, false в противном случаеtrue if x is less than or equal to y, false otherwise
x >= y true Если x больше или равно y, false в противном случаеtrue if x is greater than or equal to y, false otherwise

Операторы сравнения целое числоInteger comparison operators

Ниже перечислены операторы сравнения предопределенные целочисленные.The predefined integer comparison operators are:

bool operator ==(int x, int y);
bool operator ==(uint x, uint y);
bool operator ==(long x, long y);
bool operator ==(ulong x, ulong y);

bool operator !=(int x, int y);
bool operator !=(uint x, uint y);
bool operator !=(long x, long y);
bool operator !=(ulong x, ulong y);

bool operator <(int x, int y);
bool operator <(uint x, uint y);
bool operator <(long x, long y);
bool operator <(ulong x, ulong y);

bool operator >(int x, int y);
bool operator >(uint x, uint y);
bool operator >(long x, long y);
bool operator >(ulong x, ulong y);

bool operator <=(int x, int y);
bool operator <=(uint x, uint y);
bool operator <=(long x, long y);
bool operator <=(ulong x, ulong y);

bool operator >=(int x, int y);
bool operator >=(uint x, uint y);
bool operator >=(long x, long y);
bool operator >=(ulong x, ulong y);

Каждый из этих операторов сравнивает числовые значения двух целочисленных операндов и возвращает bool значение, указывающее, является ли соответствующее отношение true или false.Each of these operators compares the numeric values of the two integer operands and returns a bool value that indicates whether the particular relation is true or false.

Операторы сравнения с плавающей запятойFloating-point comparison operators

Ниже перечислены операторы предопределенные сравнения с плавающей запятой.The predefined floating-point comparison operators are:

bool operator ==(float x, float y);
bool operator ==(double x, double y);

bool operator !=(float x, float y);
bool operator !=(double x, double y);

bool operator <(float x, float y);
bool operator <(double x, double y);

bool operator >(float x, float y);
bool operator >(double x, double y);

bool operator <=(float x, float y);
bool operator <=(double x, double y);

bool operator >=(float x, float y);
bool operator >=(double x, double y);

Операторы сравнивают операнды в соответствии с правилами стандарта IEEE 754:The operators compare the operands according to the rules of the IEEE 754 standard:

  • Если один из операндов имеет значение NaN, результатом является false для всех операторов, за исключением !=, для которого получается true.If either operand is NaN, the result is false for all operators except !=, for which the result is true. Для любых двух операндов x != y всегда дает тот же результат, как !(x == y).For any two operands, x != y always produces the same result as !(x == y). Тем не менее, в том случае, когда один или оба операнда имеют значения NaN, <, >, <=, и >= операторы не производят те же результаты, что логическое отрицание оператора.However, when one or both operands are NaN, the <, >, <=, and >= operators do not produce the same results as the logical negation of the opposite operator. Например, если любой из x и y имеет значение NaN, затем x < yfalse, но !(x >= y) является true.For example, if either of x and y is NaN, then x < y is false, but !(x >= y) is true.

  • Если ни один из операндов имеет значение NaN, операторы сравнения значений двух операндов с плавающей запятой с точки зрения упорядочениеWhen neither operand is NaN, the operators compare the values of the two floating-point operands with respect to the ordering

    -inf < -max < ... < -min < -0.0 == +0.0 < +min < ... < +max < +inf
    

    где min и max являются наименьшую и наибольшую положительными значениями, которые могут быть представлены в заданном формате с плавающей запятой.where min and max are the smallest and largest positive finite values that can be represented in the given floating-point format. Ниже приведены важные последствия этот порядок.Notable effects of this ordering are:

    • Положительные и отрицательные нули, считаются равными.Negative and positive zeros are considered equal.
    • Отрицательная бесконечность, считается меньше, чем все остальные значения, но равным другой минус бесконечности.A negative infinity is considered less than all other values, but equal to another negative infinity.
    • Положительная бесконечность считается больше, чем все остальные значения, но равным другой положительной бесконечности.A positive infinity is considered greater than all other values, but equal to another positive infinity.

Операторы сравнения десятичных чиселDecimal comparison operators

Ниже перечислены операторы сравнения предопределенные десятичных чисел.The predefined decimal comparison operators are:

bool operator ==(decimal x, decimal y);
bool operator !=(decimal x, decimal y);
bool operator <(decimal x, decimal y);
bool operator >(decimal x, decimal y);
bool operator <=(decimal x, decimal y);
bool operator >=(decimal x, decimal y);

Каждый из этих операторов сравнивает числовые значения двух десятичных операндов и возвращает bool значение, указывающее, является ли соответствующее отношение true или false.Each of these operators compares the numeric values of the two decimal operands and returns a bool value that indicates whether the particular relation is true or false. Decimal сравнение эквивалентно значению с помощью соответствующего реляционного или оператор равенства типа System.Decimal.Each decimal comparison is equivalent to using the corresponding relational or equality operator of type System.Decimal.

Логические операторы равенстваBoolean equality operators

Ниже приведены стандартные логические операторы равенства.The predefined boolean equality operators are:

bool operator ==(bool x, bool y);
bool operator !=(bool x, bool y);

Результат ==true Если оба x и y являются true или если оба x и y являются false.The result of == is true if both x and y are true or if both x and y are false. В противном случае результат будет false.Otherwise, the result is false.

Результат !=false Если оба x и y являются true или если оба x и y являются false.The result of != is false if both x and y are true or if both x and y are false. В противном случае результат будет true.Otherwise, the result is true. Если операнды имеют тип bool, != оператор дает тот же результат, как ^ оператор.When the operands are of type bool, the != operator produces the same result as the ^ operator.

Операторы сравнения перечисленияEnumeration comparison operators

Каждый тип перечисления неявно предоставляет следующие стандартные операторы сравнения:Every enumeration type implicitly provides the following predefined comparison operators:

bool operator ==(E x, E y);
bool operator !=(E x, E y);
bool operator <(E x, E y);
bool operator >(E x, E y);
bool operator <=(E x, E y);
bool operator >=(E x, E y);

Результат вычисления x op y, где x и y являются выражениями типа перечисления E с базовым типом U, и op является один из операторов сравнения, точно так же, как Оценка ((U)x) op ((U)y).The result of evaluating x op y, where x and y are expressions of an enumeration type E with an underlying type U, and op is one of the comparison operators, is exactly the same as evaluating ((U)x) op ((U)y). Другими словами операторы сравнения для типа перечисления просто сравнивать базовые целые значения двух операндов.In other words, the enumeration type comparison operators simply compare the underlying integral values of the two operands.

Операторы равенства ссылочного типаReference type equality operators

Приведены стандартные операторы ссылочного типа проверки на равенство.The predefined reference type equality operators are:

bool operator ==(object x, object y);
bool operator !=(object x, object y);

Операторы возвращают результат сравнения двух ссылок на идентичность.The operators return the result of comparing the two references for equality or non-equality.

Так как стандартные операторы ссылочного типа равенства принимает операнды типа object, они применяются ко всем типам, не объявляйте применимо operator == и operator != членов.Since the predefined reference type equality operators accept operands of type object, they apply to all types that do not declare applicable operator == and operator != members. И наоборот любые применимые равенства, определяемые пользователем операторы скрывают стандартные операторы ссылочного типа проверки на равенство.Conversely, any applicable user-defined equality operators effectively hide the predefined reference type equality operators.

Стандартные операторы ссылочного типа равенства требуется одно из следующих:The predefined reference type equality operators require one of the following:

  • Оба операнда имеют значение типа, известные как reference_type или литерала null.Both operands are a value of a type known to be a reference_type or the literal null. Кроме того неявное преобразование (явные преобразования ссылочных типов) существует тип один из операндов на тип значение второго операнда.Furthermore, an explicit reference conversion (Explicit reference conversions) exists from the type of either operand to the type of the other operand.
  • Один операнд является значение типа T где Tпараметр_типа и другой операнд является литералом null.One operand is a value of type T where T is a type_parameter and the other operand is the literal null. Кроме того T имеет ограничение типа значения.Furthermore T does not have the value type constraint.

Если одно из этих условий не true, происходит ошибка времени привязки.Unless one of these conditions are true, a binding-time error occurs. Ниже приведены важные последствия этих правил.Notable implications of these rules are:

  • Является ошибкой времени привязки для использования стандартных операторов ссылочного типа равенства для сравнения двух ссылок, которые заведомо отличаться во время привязки.It is a binding-time error to use the predefined reference type equality operators to compare two references that are known to be different at binding-time. Например, если во время привязки типы операндов два типа класса A и Bи если ни один из A , ни B является производным от другого, то он может быть организовано два операнда для ссылки на тот же объект.For example, if the binding-time types of the operands are two class types A and B, and if neither A nor B derives from the other, then it would be impossible for the two operands to reference the same object. Таким образом операция вызовет ошибку во время привязки.Thus, the operation is considered a binding-time error.
  • Операторы равенства предопределенные ссылочного типа не допускают значение операнды типа для сравнения.The predefined reference type equality operators do not permit value type operands to be compared. Таким образом Если тип структуры объявляет свои собственные операторы равенства, он не поддерживается для сравнения значений этого типа структуры.Therefore, unless a struct type declares its own equality operators, it is not possible to compare values of that struct type.
  • Операторы равенства предопределенные ссылочного типа никогда не вызывают операции упаковки-преобразования, чтобы для своих операндов.The predefined reference type equality operators never cause boxing operations to occur for their operands. Было бы смысла для выполнения такой операции упаковки-преобразования, так как ссылки на создаваемые упакованные экземпляры обязательно будут отличаться от всех остальных ссылок.It would be meaningless to perform such boxing operations, since references to the newly allocated boxed instances would necessarily differ from all other references.
  • Если операнд с типом параметра типа T сравнивается с nullи тип времени выполнения T является типом значения, результатом сравнения является false.If an operand of a type parameter type T is compared to null, and the run-time type of T is a value type, the result of the comparison is false.

В следующем примере проверяется, является ли аргумент параметра неограниченного типа null.The following example checks whether an argument of an unconstrained type parameter type is null.

class C<T>
{
    void F(T x) {
        if (x == null) throw new ArgumentNullException();
        ...
    }
}

x == null Конструкция разрешено, даже если T может представлять тип значения, и результат просто определяется как false при T является типом значения.The x == null construct is permitted even though T could represent a value type, and the result is simply defined to be false when T is a value type.

Для операции в виде x == y или x != y, если всем применимым operator == или operator != существует, разрешение перегрузки оператора (разрешить перегрузку бинарного оператора), выберет правила оператор, а не стандартный оператор ссылочного типа проверки на равенство.For an operation of the form x == y or x != y, if any applicable operator == or operator != exists, the operator overload resolution (Binary operator overload resolution) rules will select that operator instead of the predefined reference type equality operator. Тем не менее, это всегда можно выбрать оператор равенства Предопределенная ссылка типа явным образом привести один или оба операнда к типу object.However, it is always possible to select the predefined reference type equality operator by explicitly casting one or both of the operands to type object. ПримерThe example

using System;

class Test
{
    static void Main() {
        string s = "Test";
        string t = string.Copy(s);
        Console.WriteLine(s == t);
        Console.WriteLine((object)s == t);
        Console.WriteLine(s == (object)t);
        Console.WriteLine((object)s == (object)t);
    }
}

выводятся следующие выходные данныеproduces the output

True
False
False
False

s И t переменные ссылаются на два отдельных string экземпляров, содержащую те же символы.The s and t variables refer to two distinct string instances containing the same characters. Выводит первое сравнение True так как оператор равенства заранее определенной строки (строковые операторы равенства) выбран, если оба операнда имеют тип string.The first comparison outputs True because the predefined string equality operator (String equality operators) is selected when both operands are of type string. Все оставшиеся сравнения вывода False так как стандартный оператор ссылочного типа равенства выбрана в том случае, если один или оба операнда имеют тип object.The remaining comparisons all output False because the predefined reference type equality operator is selected when one or both of the operands are of type object.

Обратите внимание на то, что указанная процедура не имеет смысла для типов значений.Note that the above technique is not meaningful for value types. ПримерThe example

class Test
{
    static void Main() {
        int i = 123;
        int j = 123;
        System.Console.WriteLine((object)i == (object)j);
    }
}

Выводит False из-за приведения создание ссылок на два отдельных экземпляра упакованных int значения.outputs False because the casts create references to two separate instances of boxed int values.

Операторы равенства строкString equality operators

Ниже перечислены операторы равенства заранее определенной строки.The predefined string equality operators are:

bool operator ==(string x, string y);
bool operator !=(string x, string y);

Два string значения считаются равными, если выполняется одно из следующих:Two string values are considered equal when one of the following is true:

  • Оба значения равны null.Both values are null.
  • Оба значения являются ненулевой ссылками на экземпляры строк с одинаковой длиной и идентичные символы в каждой позиции.Both values are non-null references to string instances that have identical lengths and identical characters in each character position.

Операторы равенства строк сравнения строковых значений, а не ссылки на строки.The string equality operators compare string values rather than string references. Если два разных экземпляра строк содержат та же последовательность символов, значения строк равны, но ссылки отличаются.When two separate string instances contain the exact same sequence of characters, the values of the strings are equal, but the references are different. Как описано в разделе операторы равенства ссылочного типа, операторы равенства ссылочного типа можно использовать для сравнения ссылки на строки вместо строковых значений.As described in Reference type equality operators, the reference type equality operators can be used to compare string references instead of string values.

Операторы равенства делегатовDelegate equality operators

Каждый тип делегата неявно предоставляет следующие стандартные операторы сравнения:Every delegate type implicitly provides the following predefined comparison operators:

bool operator ==(System.Delegate x, System.Delegate y);
bool operator !=(System.Delegate x, System.Delegate y);

Два делегата считаются равными следующим образом:Two delegate instances are considered equal as follows:

  • Если экземпляры делегата являются null, они равны, только в том случае, если выполняются оба null.If either of the delegate instances is null, they are equal if and only if both are null.
  • Если делегаты имеют другой тип времени выполнения, они никогда не равны.If the delegates have different run-time type they are never equal.
  • Если у обоих экземпляров делегата есть список вызова (объявления делегатов), то они равны только в том случае, если их списки вызовов имеют одинаковую длину и каждая запись в список вызова равно (как определено ниже) для соответствующей записи в порядке, в списке вызова другого.If both of the delegate instances have an invocation list (Delegate declarations), those instances are equal if and only if their invocation lists are the same length, and each entry in one's invocation list is equal (as defined below) to the corresponding entry, in order, in the other's invocation list.

Следующие правила определяют равенство записей списка вызова:The following rules govern the equality of invocation list entries:

  • Если две записи списка вызова ссылается на тот же статический метод, а затем записи считаются равными.If two invocation list entries both refer to the same static method then the entries are equal.
  • Если две записи списка вызова ссылаются на один и тот же метод статическим на тот же целевой объект (в соответствии с операторов равенства ссылок) записи считаются равными.If two invocation list entries both refer to the same non-static method on the same target object (as defined by the reference equality operators) then the entries are equal.
  • Полученные записи списка вызова при вычислении семантически идентичных anonymous_method_expressions или lambda_expressions с тем же набором (возможно, пустой), записанный внешней переменной. экземпляры разрешены (но не требуются) должны совпадать.Invocation list entries produced from evaluation of semantically identical anonymous_method_expressions or lambda_expressions with the same (possibly empty) set of captured outer variable instances are permitted (but not required) to be equal.

Операторы равенства и значение nullEquality operators and null

== И != операторы позволяют один операнд должен быть значение типа, допускающего значение NULL, а другой быть null литерал, даже если существует предопределенные или определяемые пользователем оператор не (обычного или с ликвидированный формы) для операции.The == and != operators permit one operand to be a value of a nullable type and the other to be the null literal, even if no predefined or user-defined operator (in unlifted or lifted form) exists for the operation.

Для операции в одной из формFor an operation of one of the forms

x == null
null == x
x != null
null != x

где x — это выражение типа, допускающего значение NULL, если разрешение перегрузки оператора (разрешить перегрузку бинарного оператора) не удалось найти соответствующий оператор, результат вместо этого вычисляется на основе HasValue Свойство x.where x is an expression of a nullable type, if operator overload resolution (Binary operator overload resolution) fails to find an applicable operator, the result is instead computed from the HasValue property of x. В частности, первые две формы преобразуются в !x.HasValue, и два последних преобразуются в x.HasValue.Specifically, the first two forms are translated into !x.HasValue, and last two forms are translated into x.HasValue.

Является операторомThe is operator

is Оператор используется для динамической проверки, совместим ли тип времени выполнения объекта с заданным типом.The is operator is used to dynamically check if the run-time type of an object is compatible with a given type. Результат операции E is T, где E — это выражение и T — это тип, возвращается логическое значение, указывающее, ли E можно успешно преобразовать в тип T с помощью преобразования ссылок, упаковки-преобразования преобразования или распаковки-преобразования.The result of the operation E is T, where E is an expression and T is a type, is a boolean value indicating whether E can successfully be converted to type T by a reference conversion, a boxing conversion, or an unboxing conversion. После замены аргументов типа для всех параметров типа, операция вычисляется следующим образом:The operation is evaluated as follows, after type arguments have been substituted for all type parameters:

  • Если E является анонимной функцией, возникает ошибка времени компиляцииIf E is an anonymous function, a compile-time error occurs
  • Если E является группой методов или null литерал, если тип E — это ссылочный тип или тип, допускающий значение NULL и значение E имеет значение null, результат имеет значение false.If E is a method group or the null literal, of if the type of E is a reference type or a nullable type and the value of E is null, the result is false.
  • В противном случае позволить D представляют динамический тип E следующим образом:Otherwise, let D represent the dynamic type of E as follows:
    • Если тип E является ссылочным типом, D является типом времени выполнения ссылка на экземпляр, E.If the type of E is a reference type, D is the run-time type of the instance reference by E.
    • Если тип E является тип nullable D — базовый тип этого типа, допускающего значение NULL.If the type of E is a nullable type, D is the underlying type of that nullable type.
    • Если тип E является типом значения, не допускающие значения NULL, D — это тип E.If the type of E is a non-nullable value type, D is the type of E.
  • Результат операции зависит от D и T следующим образом:The result of the operation depends on D and T as follows:
    • Если T является ссылочным типом, результат равен true, если D и T относятся к одному типу, в том случае, если D является ссылочным типом и и неявное ссылочное преобразование из D для T существует, или если D является типом значения и преобразования-упаковки из D для T существует.If T is a reference type, the result is true if D and T are the same type, if D is a reference type and an implicit reference conversion from D to T exists, or if D is a value type and a boxing conversion from D to T exists.
    • Если T является типом, допускающий значение NULL, результат равен true, если D является базовым типом объекта T.If T is a nullable type, the result is true if D is the underlying type of T.
    • Если T является типом значения, не допускающие значения NULL, результат равен true, если D и T относятся к одному типу.If T is a non-nullable value type, the result is true if D and T are the same type.
    • В противном случае результат имеет значение false.Otherwise, the result is false.

Обратите внимание, что пользовательские преобразования не рассматривает is оператор.Note that user defined conversions, are not considered by the is operator.

Оператор asThe as operator

as Оператор используется для явного преобразования значения в указанный ссылочный тип или тип, допускающий значение NULL.The as operator is used to explicitly convert a value to a given reference type or nullable type. В отличие от выражения приведения (выражения приведения), as оператор никогда не создает исключение.Unlike a cast expression (Cast expressions), the as operator never throws an exception. Вместо этого, если указанное преобразование невозможно, то результирующее значение равно null.Instead, if the indicated conversion is not possible, the resulting value is null.

В операции формы E as T, E должно быть выражением и T должен быть ссылочного типа, параметром типа, быть ссылочным типом или типом, допускающий значение NULL.In an operation of the form E as T, E must be an expression and T must be a reference type, a type parameter known to be a reference type, or a nullable type. Кроме того по крайней мере одно из следующих должен иметь значение true, или иначе возникает ошибка времени компиляции:Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs:

Если тип времени компиляции E не dynamic, операция E as T дает тот же результат, какIf the compile-time type of E is not dynamic, the operation E as T produces the same result as

E is T ? (T)(E) : (T)null

за исключением того, что E вычисляется только один раз.except that E is only evaluated once. Компилятор может проводить оптимизацию E as T для проверки не более одного динамического типа в отличие от двух динамических проверок типа в расширении выше.The compiler can be expected to optimize E as T to perform at most one dynamic type check as opposed to the two dynamic type checks implied by the expansion above.

Если тип времени компиляции Edynamic, в отличие от оператора приведения as оператор не имеет динамической привязки (динамической привязки).If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound (Dynamic binding). Поэтому расширение в данном случае является:Therefore the expansion in this case is:

E is T ? (T)(object)(E) : (T)null

Обратите внимание, что некоторые преобразования, например определенные пользователем, не поддерживаемых в средстве as оператор и следует выполнять с помощью выражения приведения.Note that some conversions, such as user defined conversions, are not possible with the as operator and should instead be performed using cast expressions.

В примереIn the example

class X
{

    public string F(object o) {
        return o as string;        // OK, string is a reference type
    }

    public T G<T>(object o) where T: Attribute {
        return o as T;             // Ok, T has a class constraint
    }

    public U H<U>(object o) {
        return o as U;             // Error, U is unconstrained 
    }
}

параметр типа T из G известно, быть ссылочным типом, так как он имеет ограничения класса.the type parameter T of G is known to be a reference type, because it has the class constraint. Параметр типа U из H не является тем не менее, поэтому использование as оператор в H запрещено.The type parameter U of H is not however; hence the use of the as operator in H is disallowed.

Логические операторыLogical operators

&, ^, И | называются логическими операторами.The &, ^, and | operators are called the logical operators.

and_expression
    : equality_expression
    | and_expression '&' equality_expression
    ;

exclusive_or_expression
    : and_expression
    | exclusive_or_expression '^' and_expression
    ;

inclusive_or_expression
    : exclusive_or_expression
    | inclusive_or_expression '|' exclusive_or_expression
    ;

Если операнд логического оператора имеет тип времени компиляции dynamic, а затем он динамически связан (динамической привязки).If an operand of a logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). В данном случае является типов во время компиляции выражения dynamic, а разрешение, приведенное ниже будет иметь место во время выполнения, используя тип времени выполнения операндов, имеющих указанный тип времени компиляции dynamic.In this case the compile-time type of the expression is dynamic, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic.

Для операции в виде x op y, где op является одним из логических операторов, разрешение перегрузки (разрешить перегрузку бинарного оператора) применяется, чтобы выбрать конкретную реализацию оператора.For an operation of the form x op y, where op is one of the logical operators, overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Операнды преобразуются в типы параметров выбранного оператора и типом результата является тип возвращаемого значения оператора.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Стандартные логические операторы описаны в следующих разделах.The predefined logical operators are described in the following sections.

Логические операторы целое числоInteger logical operators

Предопределенные целочисленные перечислены логические операторы:The predefined integer logical operators are:

int operator &(int x, int y);
uint operator &(uint x, uint y);
long operator &(long x, long y);
ulong operator &(ulong x, ulong y);

int operator |(int x, int y);
uint operator |(uint x, uint y);
long operator |(long x, long y);
ulong operator |(ulong x, ulong y);

int operator ^(int x, int y);
uint operator ^(uint x, uint y);
long operator ^(long x, long y);
ulong operator ^(ulong x, ulong y);

& Оператор выполняет побитовую операцию логического AND двух операндов, | оператор выполняет побитовую операцию логического OR двух операндов и ^ оператор вычисляет побитового логического исключающего OR двух операндов.The & operator computes the bitwise logical AND of the two operands, the | operator computes the bitwise logical OR of the two operands, and the ^ operator computes the bitwise logical exclusive OR of the two operands. Не порождают переполнения из этих операций.No overflows are possible from these operations.

Логические операторы перечисленияEnumeration logical operators

Каждый тип перечисления E неявно предоставляет следующие предварительно определенные логические операторы:Every enumeration type E implicitly provides the following predefined logical operators:

E operator &(E x, E y);
E operator |(E x, E y);
E operator ^(E x, E y);

Результат вычисления x op y, где x и y являются выражениями типа перечисления E с базовым типом U, и op является одним из логических операторов, именно так же, как Оценка (E)((U)x op (U)y).The result of evaluating x op y, where x and y are expressions of an enumeration type E with an underlying type U, and op is one of the logical operators, is exactly the same as evaluating (E)((U)x op (U)y). Другими словами логические операторы типа перечисления просто выполняют логические операции в базовом типе двух операндов.In other words, the enumeration type logical operators simply perform the logical operation on the underlying type of the two operands.

Логические операторыBoolean logical operators

Ниже приведены стандартные логические операторы.The predefined boolean logical operators are:

bool operator &(bool x, bool y);
bool operator |(bool x, bool y);
bool operator ^(bool x, bool y);

Результат операции x & y принимает значение true, если оба оператора x и y имеют значение true.The result of x & y is true if both x and y are true. В противном случае результат будет false.Otherwise, the result is false.

Результат x | ytrue Если x или y является true.The result of x | y is true if either x or y is true. В противном случае результат будет false.Otherwise, the result is false.

Результат x ^ ytrue Если xtrue и yfalse, или xfalse и y является true.The result of x ^ y is true if x is true and y is false, or x is false and y is true. В противном случае результат будет false.Otherwise, the result is false. Если операнды имеют тип bool, ^ оператор вычисляет тот же результат, как != оператор.When the operands are of type bool, the ^ operator computes the same result as the != operator.

Обнуляемые логические операторыNullable boolean logical operators

Допускающий значение NULL тип данных boolean bool? может представлять три значения true, false, и nullи принципиально подобен классу для трех значений типа, используемого для логических выражений в SQL.The nullable boolean type bool? can represent three values, true, false, and null, and is conceptually similar to the three-valued type used for boolean expressions in SQL. Чтобы убедиться, что результаты & и | операторов для bool? операндов, соответствуют SQL троичную логику, предоставляются следующие предопределенные операторы:To ensure that the results produced by the & and | operators for bool? operands are consistent with SQL's three-valued logic, the following predefined operators are provided:

bool? operator &(bool? x, bool? y);
bool? operator |(bool? x, bool? y);

В следующей таблице перечислены результаты этих операторов для всех сочетаний значений true, false, и null.The following table lists the results produced by these operators for all combinations of the values true, false, and null.

x y x & y x | y
true true true true
true false false true
true null null true
false true false true
false false false false
false null false null
null true null true
null false false null
null null null null

Условные логические операторыConditional logical operators

&& И || называются условные логические операторы.The && and || operators are called the conditional logical operators. Они также называются «Упрощенные» логические операторы.They are also called the "short-circuiting" logical operators.

conditional_and_expression
    : inclusive_or_expression
    | conditional_and_expression '&&' inclusive_or_expression
    ;

conditional_or_expression
    : conditional_and_expression
    | conditional_or_expression '||' conditional_and_expression
    ;

&& И || операторы представляют собой условное версии & и | операторы:The && and || operators are conditional versions of the & and | operators:

  • Операция x && y соответствующей операции x & y, за исключением того, что y вычисляется только в том случае, если x не false.The operation x && y corresponds to the operation x & y, except that y is evaluated only if x is not false.
  • Операция x || y соответствующей операции x | y, за исключением того, что y вычисляется только в том случае, если x не true.The operation x || y corresponds to the operation x | y, except that y is evaluated only if x is not true.

Если операнд условного логического оператора имеет тип времени компиляции dynamic, а затем он динамически связан (динамической привязки).If an operand of a conditional logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). В данном случае является типов во время компиляции выражения dynamic, а разрешение, приведенное ниже будет иметь место во время выполнения, используя тип времени выполнения операндов, имеющих указанный тип времени компиляции dynamic.In this case the compile-time type of the expression is dynamic, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic.

Операции формы x && y или x || y обрабатывается с применением разрешение перегрузки (разрешить перегрузку бинарного оператора) как если бы операция была x & y или x | y.An operation of the form x && y or x || y is processed by applying overload resolution (Binary operator overload resolution) as if the operation was written x & y or x | y. Затем,Then,

Это не позволяет непосредственно перегрузить условные логические операторы.It is not possible to directly overload the conditional logical operators. Тем не менее поскольку условные логические операторы вычисляются с точки зрения регулярных логических операторов, перегрузки регулярных логических операторов с некоторыми ограничениями, считаться перегрузками условных логических операторов.However, because the conditional logical operators are evaluated in terms of the regular logical operators, overloads of the regular logical operators are, with certain restrictions, also considered overloads of the conditional logical operators. Это описано далее в пользовательские условные логические операторы.This is described further in User-defined conditional logical operators.

Условные логические операторыBoolean conditional logical operators

При операндов && или || относятся к типу bool, или если операнды имеют типы, которые не определяют соответствующем operator & или operator |, но определить неявные преобразования в bool, операция обработан следующим образом:When the operands of && or || are of type bool, or when the operands are of types that do not define an applicable operator & or operator |, but do define implicit conversions to bool, the operation is processed as follows:

  • Операция x && y вычисляется как x ? y : false.The operation x && y is evaluated as x ? y : false. Другими словами x сначала вычисляется и преобразуется в тип bool.In other words, x is first evaluated and converted to type bool. Затем, если xtrue, y вычисляется и преобразуется в тип bool, и это становится результатом операции.Then, if x is true, y is evaluated and converted to type bool, and this becomes the result of the operation. В противном случае результатом операции является false.Otherwise, the result of the operation is false.
  • Операция x || y вычисляется как x ? true : y.The operation x || y is evaluated as x ? true : y. Другими словами x сначала вычисляется и преобразуется в тип bool.In other words, x is first evaluated and converted to type bool. Затем, если xtrue, результатом операции является true.Then, if x is true, the result of the operation is true. В противном случае y вычисляется и преобразуется в тип bool, и это становится результатом операции.Otherwise, y is evaluated and converted to type bool, and this becomes the result of the operation.

Пользовательские условные логические операторыUser-defined conditional logical operators

Когда операндов && или || типов, которые объявляют соответствующем определяются пользователем operator & или operator |, оба следующих должен иметь значение true, где T является типом, в котором объявлен выбранного оператора:When the operands of && or || are of types that declare an applicable user-defined operator & or operator |, both of the following must be true, where T is the type in which the selected operator is declared:

  • Тип возвращаемого значения и тип каждого параметра, выбранного оператора должны быть T.The return type and the type of each parameter of the selected operator must be T. Другими словами, следует вычислять логического оператора AND или логической OR двух операндов типа Tи должен возвращать результат типа T.In other words, the operator must compute the logical AND or the logical OR of two operands of type T, and must return a result of type T.
  • T должен содержать объявления operator true и operator false.T must contain declarations of operator true and operator false.

Ошибка времени привязки возникает, если любой из этих требований не выполнено.A binding-time error occurs if either of these requirements is not satisfied. В противном случае && или || операция вычисляется путем объединения, определяемые пользователем operator true или operator false с выбранной определяемого пользователем оператора:Otherwise, the && or || operation is evaluated by combining the user-defined operator true or operator false with the selected user-defined operator:

  • Операция x && y вычисляется как T.false(x) ? x : T.&(x, y), где T.false(x) является вызовом operator false объявленные в T, и T.&(x, y) является вызовом выбранного operator &.The operation x && y is evaluated as T.false(x) ? x : T.&(x, y), where T.false(x) is an invocation of the operator false declared in T, and T.&(x, y) is an invocation of the selected operator &. Другими словами x сначала оценивается и operator false вызывается на результат на предмет x имеет значение false.In other words, x is first evaluated and operator false is invoked on the result to determine if x is definitely false. Затем, если x имеет значение false, результатом операции является значение, ранее вычисленное для x.Then, if x is definitely false, the result of the operation is the value previously computed for x. В противном случае y вычисляется и выбранным operator & вызывается на значение, ранее вычисленное для x и вычисленного значения y для получения результата операции.Otherwise, y is evaluated, and the selected operator & is invoked on the value previously computed for x and the value computed for y to produce the result of the operation.
  • Операция x || y вычисляется как T.true(x) ? x : T.|(x, y), где T.true(x) является вызовом operator true объявленные в T, и T.|(x,y) является вызовом выбранного operator|.The operation x || y is evaluated as T.true(x) ? x : T.|(x, y), where T.true(x) is an invocation of the operator true declared in T, and T.|(x,y) is an invocation of the selected operator|. Другими словами x сначала оценивается и operator true вызывается на результат на предмет x имеет значение true.In other words, x is first evaluated and operator true is invoked on the result to determine if x is definitely true. Затем, если x имеет значение true, результатом операции является значение, ранее вычисленное для x.Then, if x is definitely true, the result of the operation is the value previously computed for x. В противном случае y вычисляется и выбранным operator | вызывается на значение, ранее вычисленное для x и вычисленного значения y для получения результата операции.Otherwise, y is evaluated, and the selected operator | is invoked on the value previously computed for x and the value computed for y to produce the result of the operation.

В этих операций, выражение в x только вычисляется один раз и выражение в y либо не вычисляется или вычисляется только один раз.In either of these operations, the expression given by x is only evaluated once, and the expression given by y is either not evaluated or evaluated exactly once.

Например, тип, реализующий operator true и operator false, см. в разделе базы данных логического типа.For an example of a type that implements operator true and operator false, see Database boolean type.

Оператор объединения со значением nullThe null coalescing operator

?? Оператор был вызван оператор объединения со значением null.The ?? operator is called the null coalescing operator.

null_coalescing_expression
    : conditional_or_expression
    | conditional_or_expression '??' null_coalescing_expression
    ;

Null объединения со значением выражения вида a ?? b требует a как обнуляемый тип или ссылку.A null coalescing expression of the form a ?? b requires a to be of a nullable type or reference type. Если a отлично от NULL, результат a ?? ba; в противном случае результатом является b.If a is non-null, the result of a ?? b is a; otherwise, the result is b. Эта операция проверяет b только если a имеет значение null.The operation evaluates b only if a is null.

Оператор объединения со значением null является правоассоциативным, это означает, что операции группируются слева направо.The null coalescing operator is right-associative, meaning that operations are grouped from right to left. Например, выражение в форме a ?? b ?? c вычисляется как a ?? (b ?? c).For example, an expression of the form a ?? b ?? c is evaluated as a ?? (b ?? c). В целом, условия выражения формы E1 ?? E2 ?? ... ?? En возвращаются первые операндов, отличных от null, или значение null, если все операнды имеют значение null.In general terms, an expression of the form E1 ?? E2 ?? ... ?? En returns the first of the operands that is non-null, or null if all operands are null.

Тип выражения a ?? b зависит от того, какие неявные преобразования доступны с операндами.The type of the expression a ?? b depends on which implicit conversions are available on the operands. В порядке предпочтения, тип a ?? bA0, A, или B, где A — это тип a (при условии, что a с типом), B — это тип b () при условии, что b с типом), и A0 является базовым типом объекта A Если A является типом, допускающий значение NULL, или A в противном случае.In order of preference, the type of a ?? b is A0, A, or B, where A is the type of a (provided that a has a type), B is the type of b (provided that b has a type), and A0 is the underlying type of A if A is a nullable type, or A otherwise. В частности a ?? b обрабатывается следующим образом:Specifically, a ?? b is processed as follows:

  • Если A существует и не является обнуляемым типом или ссылочным типом, возникает ошибка времени компиляции.If A exists and is not a nullable type or a reference type, a compile-time error occurs.
  • Если b является динамическим выражением, тип результата — dynamic.If b is a dynamic expression, the result type is dynamic. Во время выполнения a сначала оценивается.At run-time, a is first evaluated. Если a не равно null, a преобразуется в динамический, и это становится результатом.If a is not null, a is converted to dynamic, and this becomes the result. В противном случае b вычисляется, и это становится результатом.Otherwise, b is evaluated, and this becomes the result.
  • В противном случае, если A существует и допускает значение NULL, и существует неявное преобразование из b для A0, тип результата — A0.Otherwise, if A exists and is a nullable type and an implicit conversion exists from b to A0, the result type is A0. Во время выполнения a сначала оценивается.At run-time, a is first evaluated. Если a не равно null, a распаковывается в тип A0, и это становится результатом.If a is not null, a is unwrapped to type A0, and this becomes the result. В противном случае b вычисляется и преобразуется в тип A0, и это становится результатом.Otherwise, b is evaluated and converted to type A0, and this becomes the result.
  • В противном случае, если A существует и существует неявное преобразование из b для A, тип результата — A.Otherwise, if A exists and an implicit conversion exists from b to A, the result type is A. Во время выполнения a сначала оценивается.At run-time, a is first evaluated. Если a не равно null, a становится результатом.If a is not null, a becomes the result. В противном случае b вычисляется и преобразуется в тип A, и это становится результатом.Otherwise, b is evaluated and converted to type A, and this becomes the result.
  • В противном случае, если b с типом B и существует неявное преобразование из a для B, тип результата — B.Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B. Во время выполнения a сначала оценивается.At run-time, a is first evaluated. Если a не равно null, a распаковывается в тип A0 (если A существует и допускает значения NULL) и он преобразуется в тип B, и это становится результатом.If a is not null, a is unwrapped to type A0 (if A exists and is nullable) and converted to type B, and this becomes the result. В противном случае b вычисляется и становится результатом.Otherwise, b is evaluated and becomes the result.
  • В противном случае a и b являются несовместимыми и ошибка времени компиляции возникает.Otherwise, a and b are incompatible, and a compile-time error occurs.

Условный операторConditional operator

?: Оператор был вызван условного оператора.The ?: operator is called the conditional operator. Также в некоторых случаях он называется троичный оператор.It is at times also called the ternary operator.

conditional_expression
    : null_coalescing_expression
    | null_coalescing_expression '?' expression ':' expression
    ;

Условное выражение в форме b ? x : y сначала оценивает условие b.A conditional expression of the form b ? x : y first evaluates the condition b. Затем, если btrue, x вычисляется и становится результатом операции.Then, if b is true, x is evaluated and becomes the result of the operation. В противном случае y вычисляется и становится результатом операции.Otherwise, y is evaluated and becomes the result of the operation. Условное выражение вычислено, никогда не оба x и y.A conditional expression never evaluates both x and y.

Условный оператор имеет правую ассоциативность, это означает, что операции группируются слева направо.The conditional operator is right-associative, meaning that operations are grouped from right to left. Например, выражение в форме a ? b : c ? d : e вычисляется как a ? b : (c ? d : e).For example, an expression of the form a ? b : c ? d : e is evaluated as a ? b : (c ? d : e).

Первый операнд ?: оператор должен быть выражением, которое может быть неявно преобразован в bool, или выражение типа, который реализует operator true.The first operand of the ?: operator must be an expression that can be implicitly converted to bool, or an expression of a type that implements operator true. Если не выполняется ни одно из этих требований, возникает ошибка времени компиляции.If neither of these requirements is satisfied, a compile-time error occurs.

Второй и третий операнды, x и y, из ?: оператор управления тип условного выражения.The second and third operands, x and y, of the ?: operator control the type of the conditional expression.

  • Если x имеет тип X и y имеет тип Y затемIf x has type X and y has type Y then
    • Если неявное преобразование (неявные преобразования) существует из X для Y, но не из Y для X, затем Y тип условного выражения.If an implicit conversion (Implicit conversions) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.
    • Если неявное преобразование (неявные преобразования) существует из Y для X, но не из X для Y, затем X тип условного выражения.If an implicit conversion (Implicit conversions) exists from Y to X, but not from X to Y, then X is the type of the conditional expression.
    • В противном случае можно определить тип выражения, и возникает ошибка времени компиляции.Otherwise, no expression type can be determined, and a compile-time error occurs.
  • Если только один из x и y имеет тип и оба x и y, из неявно преобразуются к этому типу, а затем этот тип условного выражения.If only one of x and y has a type, and both x and y, of are implicitly convertible to that type, then that is the type of the conditional expression.
  • В противном случае можно определить тип выражения, и возникает ошибка времени компиляции.Otherwise, no expression type can be determined, and a compile-time error occurs.

Обработка времени выполнения условного выражения формы b ? x : y состоит из следующих действий:The run-time processing of a conditional expression of the form b ? x : y consists of the following steps:

  • Во-первых, b вычисляется и bool значение b определяется:First, b is evaluated, and the bool value of b is determined:
    • Если неявное преобразование из типа b для bool существует, то это неявное преобразование выполняется для создания bool значение.If an implicit conversion from the type of b to bool exists, then this implicit conversion is performed to produce a bool value.
    • В противном случае operator true определяется тип b вызываемый для получения bool значение.Otherwise, the operator true defined by the type of b is invoked to produce a bool value.
  • Если bool является значение, созданное на предыдущем шаге true, затем x вычисляется и преобразуется в тип условного выражения, и это становится результатом условного выражения.If the bool value produced by the step above is true, then x is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression.
  • В противном случае y вычисляется и преобразуется в тип условного выражения, и это становится результатом условного выражения.Otherwise, y is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression.

Выражения анонимных функцийAnonymous function expressions

Анонимная функция выражение, которое представляет определение метода «в строке».An anonymous function is an expression that represents an "in-line" method definition. Анонимная функция не имеет значения или тип само по себе, но можно преобразовать в совместимый тип делегата или выражения дерева.An anonymous function does not have a value or type in and of itself, but is convertible to a compatible delegate or expression tree type. Вычисление преобразование анонимной функции зависит от целевой тип преобразования: Если он является типом делегата, преобразование результатом которого является значение делегата, ссылке на метод, который определяет анонимной функции.The evaluation of an anonymous function conversion depends on the target type of the conversion: If it is a delegate type, the conversion evaluates to a delegate value referencing the method which the anonymous function defines. Если это тип дерева выражения, то результатом преобразования в дерево выражения, которое представляет структуру метода в виде структуры объекта.If it is an expression tree type, the conversion evaluates to an expression tree which represents the structure of the method as an object structure.

По историческим причинам существует два синтаксический варианта анонимных функций, а именно lambda_expressions и anonymous_method_expressions.For historical reasons there are two syntactic flavors of anonymous functions, namely lambda_expressions and anonymous_method_expressions. Практически для любых целей lambda_expressions являются более четкими и выразительной, чем anonymous_method_expressions, которые остаются в язык для обеспечения обратной совместимости.For almost all purposes, lambda_expressions are more concise and expressive than anonymous_method_expressions, which remain in the language for backwards compatibility.

lambda_expression
    : anonymous_function_signature '=>' anonymous_function_body
    ;

anonymous_method_expression
    : 'delegate' explicit_anonymous_function_signature? block
    ;

anonymous_function_signature
    : explicit_anonymous_function_signature
    | implicit_anonymous_function_signature
    ;

explicit_anonymous_function_signature
    : '(' explicit_anonymous_function_parameter_list? ')'
    ;

explicit_anonymous_function_parameter_list
    : explicit_anonymous_function_parameter (',' explicit_anonymous_function_parameter)*
    ;

explicit_anonymous_function_parameter
    : anonymous_function_parameter_modifier? type identifier
    ;

anonymous_function_parameter_modifier
    : 'ref'
    | 'out'
    ;

implicit_anonymous_function_signature
    : '(' implicit_anonymous_function_parameter_list? ')'
    | implicit_anonymous_function_parameter
    ;

implicit_anonymous_function_parameter_list
    : implicit_anonymous_function_parameter (',' implicit_anonymous_function_parameter)*
    ;

implicit_anonymous_function_parameter
    : identifier
    ;

anonymous_function_body
    : expression
    | block
    ;

=> Оператор имеет тот же приоритет, как и присваивание (=) и являе