{1>Wyrażenia<1}Expressions

Wyrażenie jest sekwencją operatorów i argumentów operacji.An expression is a sequence of operators and operands. Ten rozdział definiuje składnię, kolejność oceny argumentów operacji i operatorów oraz znaczenie wyrażeń.This chapter defines the syntax, order of evaluation of operands and operators, and meaning of expressions.

Klasyfikacje wyrażeńExpression classifications

Wyrażenie jest klasyfikowane jako jedno z następujących:An expression is classified as one of the following:

  • Wartość.A value. Każda wartość ma skojarzony typ.Every value has an associated type.
  • Zmienna.A variable. Każda zmienna ma skojarzony typ, a mianowicie zadeklarowany typ zmiennej.Every variable has an associated type, namely the declared type of the variable.
  • Przestrzeń nazw.A namespace. Wyrażenie z tą klasyfikacją może występować tylko jako lewa strona member_access (dostęp do elementu członkowskiego).An expression with this classification can only appear as the left hand side of a member_access (Member access). W każdym innym kontekście wyrażenie sklasyfikowane jako przestrzeń nazw powoduje błąd w czasie kompilacji.In any other context, an expression classified as a namespace causes a compile-time error.
  • Typ.A type. Wyrażenie z tą klasyfikacją może występować tylko jako lewa strona member_access (dostęp do składowej) lub jako operand dla operatora as (operator as), operator is (operator is) lub operator typeof (operator 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). W każdym innym kontekście wyrażenie sklasyfikowane jako typ powoduje błąd w czasie kompilacji.In any other context, an expression classified as a type causes a compile-time error.
  • Grupa metod, która jest zestawem przeciążonych metod wynikających z odnośnika elementu członkowskiego (wyszukiwanie elementu członkowskiego).A method group, which is a set of overloaded methods resulting from a member lookup (Member lookup). Grupa metod może mieć skojarzone wyrażenie wystąpienia i listę powiązanych argumentów typu.A method group may have an associated instance expression and an associated type argument list. Gdy wywoływana jest metoda wystąpienia, wynik oceny wyrażenia wystąpienia zmieni się na wystąpienie reprezentowane przez this (ten dostęp).When an instance method is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access). Grupa metod jest dozwolona w invocation_expression (wyrażenia wywołania), delegate_creation_expression (wyrażenia tworzenia delegatów) i jako lewa strona operatora is i może być niejawnie konwertowana na zgodny typ delegata (konwersje grup metod).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). W każdym innym kontekście wyrażenie sklasyfikowane jako grupa metod powoduje błąd w czasie kompilacji.In any other context, an expression classified as a method group causes a compile-time error.
  • Literał o wartości null.A null literal. Wyrażenie z tą klasyfikacją może być niejawnie konwertowane na typ referencyjny lub typ dopuszczający wartość null.An expression with this classification can be implicitly converted to a reference type or nullable type.
  • Funkcja anonimowa.An anonymous function. Wyrażenie z tą klasyfikacją może być niejawnie konwertowane na zgodny typ delegata lub typ drzewa wyrażenia.An expression with this classification can be implicitly converted to a compatible delegate type or expression tree type.
  • Dostęp do właściwości.A property access. Każdy dostęp do właściwości ma skojarzony typ, a nie typ właściwości.Every property access has an associated type, namely the type of the property. Ponadto dostęp do właściwości może mieć skojarzone wyrażenie wystąpienia.Furthermore, a property access may have an associated instance expression. Gdy wywoływana jest metoda dostępu (get lub set bloku) właściwości wystąpienia, wynik oceny wyrażenia wystąpienia zostaje przywoływany przez this (dostęp).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).
  • Dostęp do zdarzenia.An event access. Każdy dostęp do zdarzenia ma skojarzony typ, a nie typ zdarzenia.Every event access has an associated type, namely the type of the event. Ponadto dostęp do zdarzeń może mieć skojarzone wyrażenie wystąpienia.Furthermore, an event access may have an associated instance expression. Dostęp do zdarzenia może być wyświetlany jako lewy argument operacji dla operatorów += i -= (przypisanie zdarzenia).An event access may appear as the left hand operand of the += and -= operators (Event assignment). W każdym innym kontekście wyrażenie sklasyfikowane jako dostęp do zdarzenia powoduje błąd w czasie kompilacji.In any other context, an expression classified as an event access causes a compile-time error.
  • Dostęp indeksatora.An indexer access. Każdy dostęp indeksatora ma skojarzony typ, a mianowicie typ elementu indeksatora.Every indexer access has an associated type, namely the element type of the indexer. Ponadto dostęp indeksatora ma skojarzone wyrażenie wystąpienia i skojarzoną listę argumentów.Furthermore, an indexer access has an associated instance expression and an associated argument list. Gdy wywoływana jest metoda dostępu (get lub set bloku), wynik oceny wyrażenia wystąpienia zmieni się na wystąpienie reprezentowane przez this (ten dostęp), a wynik oceny listy argumentów jest listą parametrów wywołania ().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.
  • Wartość.Nothing. Dzieje się tak, gdy wyrażenie jest wywołaniem metody z typem zwracanym void.This occurs when the expression is an invocation of a method with a return type of void. Wyrażenie sklasyfikowane jako Nothing jest prawidłowe tylko w kontekście statement_expression (instrukcji wyrażeń).An expression classified as nothing is only valid in the context of a statement_expression (Expression statements).

Końcowy wynik wyrażenia nigdy nie jest obszarem nazw, typem, grupą metod lub dostępem do zdarzeń.The final result of an expression is never a namespace, type, method group, or event access. Zamiast tego, jak wspomniano powyżej, te kategorie wyrażeń są konstrukcjami pośrednimi, które są dozwolone tylko w określonych kontekstach.Rather, as noted above, these categories of expressions are intermediate constructs that are only permitted in certain contexts.

Dostęp do właściwości lub dostęp do indeksatora jest zawsze ponownie klasyfikowany jako wartość przez wykonanie wywołania metody dostępu get lub set metodydostępu.A property access or indexer access is always reclassified as a value by performing an invocation of the get accessor or the set accessor. Określony akcesor jest określany przez kontekst dostępu właściwości lub indeksatora: Jeśli dostęp jest elementem docelowym przypisania, metoda dostępu set jest wywoływana, aby przypisać nową wartość (przypisanie proste).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). W przeciwnym razie metoda dostępu get jest wywoływana w celu uzyskania bieżącej wartości (wartości wyrażeń).Otherwise, the get accessor is invoked to obtain the current value (Values of expressions).

Wartości wyrażeńValues of expressions

Większość konstrukcji obejmujących wyrażenie ostatecznie wymaga wyrażenia do określenia wartości.Most of the constructs that involve an expression ultimately require the expression to denote a value. W takich przypadkach, jeśli wyrażenie rzeczywiste wskazuje przestrzeń nazw, typ, grupę metod lub wartość Nothing, wystąpi błąd w czasie kompilacji.In such cases, if the actual expression denotes a namespace, a type, a method group, or nothing, a compile-time error occurs. Jeśli jednak wyrażenie oznacza dostęp do właściwości, dostęp indeksatora lub zmienną, wartość właściwości, indeksatora lub zmiennej jest niejawnie zastępowana: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:

  • Wartość zmiennej jest po prostu wartością przechowywaną obecnie w lokalizacji magazynu identyfikowanej przez zmienną.The value of a variable is simply the value currently stored in the storage location identified by the variable. Zmienna musi być traktowana jako czasowo przypisana (przypisanie), zanim będzie można uzyskać jej wartość lub w przeciwnym razie wystąpi błąd w czasie kompilacji.A variable must be considered definitely assigned (Definite assignment) before its value can be obtained, or otherwise a compile-time error occurs.
  • Wartość wyrażenia dostępu do właściwości jest uzyskiwana przez wywołanie metody dostępu get właściwości.The value of a property access expression is obtained by invoking the get accessor of the property. Jeśli właściwość nie ma metody dostępu get, wystąpi błąd w czasie kompilacji.If the property has no get accessor, a compile-time error occurs. W przeciwnym razie jest wykonywane wywołanie elementu członkowskiego (Sprawdzanie w czasie kompilacji dynamicznego rozpoznawania przeciążenia), a wynik wywołania będzie wartością wyrażenia dostępu do właściwości.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.
  • Wartość wyrażenia dostępu indeksatora jest uzyskiwana przez wywołanie metody dostępu get indeksatora.The value of an indexer access expression is obtained by invoking the get accessor of the indexer. Jeśli indeksator nie ma metody dostępu get, wystąpi błąd w czasie kompilacji.If the indexer has no get accessor, a compile-time error occurs. W przeciwnym razie wywołanie elementu członkowskiego funkcji (Sprawdzanie w czasie kompilacji dynamicznego rozpoznawania przeciążenia) jest wykonywane z listą argumentów skojarzoną z wyrażeniem dostępu indeksatora, a wynik wywołania będzie wartością wyrażenia dostępu indeksatora.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.

Statyczne i dynamiczne powiązanieStatic and Dynamic Binding

Proces określania znaczenia operacji na podstawie typu lub wartości wyrażeń elementów (argumentów, operandów, odbiorników) jest często określany jako powiązanie.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. Na przykład znaczenie wywołania metody jest określane na podstawie typu odbiorcy i argumentów.For instance the meaning of a method call is determined based on the type of the receiver and arguments. Znaczenie operatora jest określane na podstawie typu jego operandów.The meaning of an operator is determined based on the type of its operands.

W C# znaczeniu operacji jest zwykle określane w czasie kompilacji na podstawie typu czasu kompilowania jego wyrażeń składowych.In C# the meaning of an operation is usually determined at compile-time, based on the compile-time type of its constituent expressions. Podobnie, jeśli wyrażenie zawiera błąd, błąd jest wykrywany i raportowany przez kompilator.Likewise, if an expression contains an error, the error is detected and reported by the compiler. To podejście jest znane jako powiązanie statyczne.This approach is known as static binding.

Jeśli jednak wyrażenie jest wyrażeniem dynamicznym (tj. ma typ dynamic), oznacza to, że wszelkie powiązania, które uczestniczą w systemie, powinny być oparte na typie czasu wykonywania (tj. rzeczywisty typ obiektu, który jest w czasie wykonywania), a nie typ, który jest w czasie kompilacji.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. W związku z tym powiązanie takiej operacji jest odroczone do czasu, w którym operacja ma zostać wykonana podczas uruchamiania programu.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. Nazywa się to dynamicznym wiązaniem.This is referred to as dynamic binding.

Gdy operacja jest powiązana dynamicznie, w kompilatorze nie jest wykonywane żadne sprawdzenie.When an operation is dynamically bound, little or no checking is performed by the compiler. Zamiast tego, Jeśli powiązanie czasu wykonywania nie powiedzie się, błędy są raportowane jako wyjątki w czasie wykonywania.Instead if the run-time binding fails, errors are reported as exceptions at run-time.

Następujące operacje w programie C# podlegają powiązaniu:The following operations in C# are subject to binding:

  • Dostęp do elementu członkowskiego: e.MMember access: e.M
  • Wywołanie metody: e.M(e1, ..., eN)Method invocation: e.M(e1, ..., eN)
  • Delegowanie wywołania:e(e1, ..., eN)Delegate invocation:e(e1, ..., eN)
  • Dostęp do elementów: e[e1, ..., eN]Element access: e[e1, ..., eN]
  • Tworzenie obiektu: new C(e1, ..., eN)Object creation: new C(e1, ..., eN)
  • Przeciążone operatory jednoargumentowe: +, -, !, ~, ++, --, true, falseOverloaded unary operators: +, -, !, ~, ++, --, true, false
  • Przeciążone operatory binarne: +, -, *, /, %, &, &&, |, ||, ??, ^, <<, >>, ==,!=, >, <, >=, <=Overloaded binary operators: +, -, *, /, %, &, &&, |, ||, ??, ^, <<, >>, ==,!=, >, <, >=, <=
  • Operatory przypisania: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=Assignment operators: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
  • Konwersje niejawne i jawneImplicit and explicit conversions

Gdy nie są używane żadne wyrażenia dynamiczne C# , domyślnie jest to powiązanie statyczne, co oznacza, że typy wyrażeń elementów w czasie kompilacji są stosowane w procesie wyboru.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. Jeśli jednak jeden z wyrażeń składowych w wymienionych powyżej operacjach jest wyrażeniem dynamicznym, operacja jest zamiast tego dynamicznie powiązana.However, when one of the constituent expressions in the operations listed above is a dynamic expression, the operation is instead dynamically bound.

Czas powiązaniaBinding-time

Statyczne powiązanie odbywa się w czasie kompilacji, natomiast dynamiczne wiązanie odbywa się w czasie wykonywania.Static binding takes place at compile-time, whereas dynamic binding takes place at run-time. W poniższych sekcjach termin czas wiązania odnosi się do czasu kompilacji lub czasu wykonywania w zależności od tego, kiedy powiązanie ma miejsce.In the following sections, the term binding-time refers to either compile-time or run-time, depending on when the binding takes place.

Poniższy przykład ilustruje koncepcje statycznego i dynamicznego powiązania oraz czas powiązania: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)

Pierwsze dwa wywołania są statycznie powiązane: Przeciążenie Console.WriteLine jest wybierane w oparciu o typ czasu kompilacji ich argumentu.The first two calls are statically bound: the overload of Console.WriteLine is picked based on the compile-time type of their argument. W rezultacie czas powiązania to czas kompilacji.Thus, the binding-time is compile-time.

Trzecie wywołanie jest powiązane dynamicznie: Przeciążenie Console.WriteLine jest wybierane na podstawie typu czasu wykonywania tego argumentu.The third call is dynamically bound: the overload of Console.WriteLine is picked based on the run-time type of its argument. Dzieje się tak, ponieważ argument jest wyrażeniem dynamicznym — typem czasu kompilacji jest dynamic.This happens because the argument is a dynamic expression -- its compile-time type is dynamic. W rezultacie czas powiązania dla trzeciego wywołania to czas wykonywania.Thus, the binding-time for the third call is run-time.

Powiązanie dynamiczneDynamic binding

Celem powiązania dynamicznego jest umożliwienie C# programom współdziałania z obiektami dynamicznymi, np. obiektów, które nie są zgodne z normalnymi C# regułami typu System.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. Obiekty dynamiczne mogą być obiektami z innych języków programowania z różnymi typami systemów lub mogą być obiektami, które są programowo instalatorem do implementowania własnej semantyki powiązań dla różnych operacji.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.

Mechanizm, za pomocą którego obiekt dynamiczny implementuje swoją własną semantykę, ma zdefiniowaną implementację.The mechanism by which a dynamic object implements its own semantics is implementation defined. Określony interfejs — ponownie wdrożony — jest implementowany przez obiekty dynamiczne, aby sygnalizować czas C# wykonywania, który ma specjalną semantykę.A given interface -- again implementation defined -- is implemented by dynamic objects to signal to the C# run-time that they have special semantics. Z tego względu, gdy operacje na obiekcie dynamicznym są dynamicznie powiązane, ich własnej semantyki powiązania, a C# nie z określonymi w tym dokumencie, przejmowanie.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.

Chociaż celem powiązania dynamicznego jest umożliwienie współdziałania z obiektami dynamicznymi, C# zezwala na dynamiczne wiązanie dla wszystkich obiektów, niezależnie od tego, czy są one dynamiczne, czy nie.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. Pozwala to na bezproblemowe integrację obiektów dynamicznych, ponieważ wyniki operacji na nich mogą nie być obiektami dynamicznymi, ale nadal są typu nieznanego dla programisty w czasie kompilacji.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. Ponadto dynamiczne powiązanie może pomóc wyeliminować podatny na błędy kod oparty na odbiciu nawet wtedy, gdy żadne obiekty nie są obiektami dynamicznymi.Also dynamic binding can help eliminate error-prone reflection-based code even when no objects involved are dynamic objects.

W poniższych sekcjach opisano dla każdej konstrukcji w języku dokładnie, gdy jest stosowane dynamiczne wiązanie, jakie jest sprawdzanie czasu kompilacji — jeśli jest stosowana, a także wynik klasyfikacji wyników i wyrażeń w czasie kompilacji.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.

Typy wyrażeń składowychTypes of constituent expressions

Gdy operacja jest statyczna, typ wyrażenia elementu (np. odbiorca, argument, indeks lub operand) jest zawsze uznawany za typ czasu kompilacji tego wyrażenia.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.

Gdy operacja jest powiązana dynamicznie, typ wyrażenia elementu składowego jest określany na różne sposoby w zależności od typu czasu kompilacji w wyrażeniu składnika: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:

  • Wyrażenie elementu dynamic typu czasu kompilacji jest uznawane za posiadające typ wartości rzeczywistej, do której wyrażenie oblicza w czasie wykonywaniaA constituent expression of compile-time type dynamic is considered to have the type of the actual value that the expression evaluates to at runtime
  • Wyrażenie elementu składowego, którego typem czasu kompilacji jest parametr typu, jest uznawany za posiadający typ, z którym jest powiązany parametr typu w czasie wykonywaniaA 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
  • W przeciwnym razie wyrażenie składowe jest uznawane za mające typ czasu kompilacji.Otherwise the constituent expression is considered to have its compile-time type.

OperatoryOperators

Wyrażenia są zbudowane z argumentów operacji i operatorów.Expressions are constructed from operands and operators. Operatory wyrażenia wskazują operacje do zastosowania dla operandów.The operators of an expression indicate which operations to apply to the operands. Przykłady operatorów to +, -, *, /i new.Examples of operators include +, -, *, /, and new. Przykładami operandów są literały, pola, zmienne lokalne i wyrażenia.Examples of operands include literals, fields, local variables, and expressions.

Istnieją trzy rodzaje operatorów:There are three kinds of operators:

  • Operatory jednoargumentowe.Unary operators. Operatory jednoargumentowe przyjmują jeden operand i używają obu prefiksów (takich jak --x) lub notacji przyrostkowej (na przykład x++).The unary operators take one operand and use either prefix notation (such as --x) or postfix notation (such as x++).
  • Operatory binarne.Binary operators. Operatory binarne przyjmują dwa operandy i wszystkie używają notacji wrostkowe (na przykład x + y).The binary operators take two operands and all use infix notation (such as x + y).
  • Operator Trzyelementowy.Ternary operator. Tylko jeden operator Trzyelementowy, ?:, istnieje; przyjmuje trzy operandy i używa notacji wrostkowe (c ? x : y).Only one ternary operator, ?:, exists; it takes three operands and uses infix notation (c ? x : y).

Kolejność obliczania operatorów w wyrażeniu jest określana przez pierwszeństwo i łączność operatorów (pierwszeństwo operatorów i łączność).The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators (Operator precedence and associativity).

Argumenty operacji w wyrażeniu są oceniane od lewej do prawej.Operands in an expression are evaluated from left to right. Na przykład w F(i) + G(i++) * H(i)Metoda F jest wywoływana przy użyciu starej wartości i, a następnie Metoda G jest wywoływana z starą wartością i, a wreszcie Metoda H jest wywoływana z nową wartością 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. Jest to niezależne od i niepowiązane z pierwszeństwem operatorów.This is separate from and unrelated to operator precedence.

Niektóre operatory mogą być przeciążone.Certain operators can be overloaded. Przeciążanie operatora zezwala na określenie implementacji operatora zdefiniowanego przez użytkownika dla operacji, w których jeden lub oba operandy są typu klasy lub struktury zdefiniowanej przez użytkownika (przeciążanie operatora).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).

Pierwszeństwo operatorów i łącznośćOperator precedence and associativity

Gdy wyrażenie zawiera wiele operatorów pierwszeństwo operatorów określa kolejność, w jakiej są oceniane poszczególne operatory.When an expression contains multiple operators, the precedence of the operators controls the order in which the individual operators are evaluated. Na przykład wyrażenie x + y * z jest oceniane jako x + (y * z), ponieważ operator * ma wyższy priorytet niż binarny operator +.For example, the expression x + y * z is evaluated as x + (y * z) because the * operator has higher precedence than the binary + operator. Pierwszeństwo operatora jest ustanawiane przez definicję skojarzonej produkcji gramatyki.The precedence of an operator is established by the definition of its associated grammar production. Na przykład additive_expression składa się z sekwencji multiplicative_expressions oddzielonej przez + lub - operatory, dzięki czemu operatory + i - mają niższy priorytet niż operatory *, /i %.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.

Poniższa tabela podsumowuje wszystkie operatory w kolejności od najwyższego do najniższego:The following table summarizes all operators in order of precedence from highest to lowest:

ParagrafSection KategoriaCategory OperatoryOperators
Wyrażenia podstawowePrimary expressions PodstawowaPrimary 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
Operatory jednoargumentoweUnary operators JednostkUnary + - ! ~ ++x --x (T)x+ - ! ~ ++x --x (T)x
Operatory arytmetyczneArithmetic operators MnożeniowyMultiplicative * / %* / %
Operatory arytmetyczneArithmetic operators DanaAdditive + -+ -
Operatory przesunięciaShift operators ShiftShift << >><< >>
Operatory relacyjne i testowe typuRelational and type-testing operators Testowanie relacyjne i typuRelational and type testing < > <= >= is as< > <= >= is as
Operatory relacyjne i testowe typuRelational and type-testing operators RównościEquality == !=== !=
Operatory logiczneLogical operators Logicznego ANDLogical AND &
Operatory logiczneLogical operators Logicznego XORLogical XOR ^
Operatory logiczneLogical operators Logicznego ORLogical OR |
Warunkowe operatory logiczneConditional logical operators Warunkowego ANDConditional AND &&
Warunkowe operatory logiczneConditional logical operators Warunkowego ORConditional OR ||
Operator łączenia wartości nullThe null coalescing operator Łączenia wartości nullNull coalescing ??
Operator warunkowyConditional operator WarunkowyConditional ?:
Operatory przypisania, wyrażenia funkcji anonimowychAssignment operators, Anonymous function expressions Przypisanie i wyrażenie lambdaAssignment and lambda expression = *= /= %= += -= <<= >>= &= ^= |= =>= *= /= %= += -= <<= >>= &= ^= |= =>

Gdy operand występuje między dwoma operatorami o takim samym priorytecie, łączność operatorów kontroluje kolejność wykonywania operacji: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:

  • Z wyjątkiem operatorów przypisania i operatora łączenia wartości null, wszystkie operatory binarne są z lewej strony skojarzenia, co oznacza, że operacje są wykonywane od lewej do prawej.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. Na przykład x + y + z jest oceniane jako (x + y) + z.For example, x + y + z is evaluated as (x + y) + z.
  • Operatory przypisania, operator łączenia wartości null i operator warunkowy (?:) są z prawej strony skojarzenia, co oznacza, że operacje są wykonywane od prawej do lewej.The assignment operators, the null coalescing operator and the conditional operator (?:) are right-associative, meaning that operations are performed from right to left. Na przykład x = y = z jest oceniane jako x = (y = z).For example, x = y = z is evaluated as x = (y = z).

Pierwszeństwo i asocjacyjność mogą być kontrolowane za pomocą nawiasów.Precedence and associativity can be controlled using parentheses. Na przykład x + y * z najpierw mnoży y przez z , a następnie dodaje wynik do x, ale (x + y) * z najpierw dodaje x i y i następnie wynik mnoży przez 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.

Przeładowanie operatoraOperator overloading

Wszystkie operatory jednoargumentowe i binarne mają wstępnie zdefiniowane implementacje, które są automatycznie dostępne w dowolnym wyrażeniu.All unary and binary operators have predefined implementations that are automatically available in any expression. Oprócz wstępnie zdefiniowanych implementacji implementacje zdefiniowane przez użytkownika mogą być wprowadzane przez uwzględnienie deklaracji operator w klasach i strukturach (Operatory).In addition to the predefined implementations, user-defined implementations can be introduced by including operator declarations in classes and structs (Operators). Implementacje operatorów zdefiniowane przez użytkownika zawsze mają pierwszeństwo przed wstępnie zdefiniowanymi implementacjami operatorów: tylko wtedy, gdy nie istnieją żadne odpowiednie implementacje operatorów zdefiniowane przez użytkownika, zostaną uznane wstępnie zdefiniowane implementacje operatorów, zgodnie z opisem w temacie rozpoznawanie przeciążenia operatora jednoargumentowego i rozpoznawanie przeciążenia operatora binarnego.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.

Operatory jednoargumentowe z możliwością przeciążenia:The overloadable unary operators are:

+   -   !   ~   ++   --   true   false

Mimo że true i false nie są używane jawnie w wyrażeniach (i dlatego nie są uwzględnione w tabeli pierwszeństwa w priorytecie operatora i łączność), są uznawane za operatory, ponieważ są wywoływane w kilku kontekstach wyrażeń: wyrażenia logiczne (wyrażenia logiczne) i wyrażenia obejmujące warunkowe (operator warunkowy) i warunkowe operatory logiczne (warunkowe operatory logiczne).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).

Operatory binarne z możliwością przeciążenia są następujące:The overloadable binary operators are:

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

Tylko operatory wymienione powyżej mogą być przeciążone.Only the operators listed above can be overloaded. W szczególności nie jest możliwe przeciążanie dostępu do składowych, wywoływanie metody lub =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, default, asi is.In particular, it is not possible to overload member access, method invocation, or the =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, default, as, and is operators.

Gdy operator binarny jest przeciążony, odpowiedni operator przypisania, jeśli istnieje, również jest niejawnie przeciążony.When a binary operator is overloaded, the corresponding assignment operator, if any, is also implicitly overloaded. Na przykład Przeciążenie operatora * jest również przeciążeniem *=operatora.For example, an overload of operator * is also an overload of operator *=. Opisano to dokładniej w przypisaniu złożonym.This is described further in Compound assignment. Należy zauważyć, że sam operator przypisania (=) nie może być przeciążony.Note that the assignment operator itself (=) cannot be overloaded. Przypisanie zawsze wykonuje prostą kopię wartości w zmiennej.An assignment always performs a simple bit-wise copy of a value into a variable.

Operacje Cast, takie jak (T)x, są przeciążone przez dostarczanie zdefiniowanych przez użytkownika konwersji (konwersje zdefiniowane przez użytkownika).Cast operations, such as (T)x, are overloaded by providing user-defined conversions (User-defined conversions).

Dostęp do elementu, taki jak a[x], nie jest uważany za operatora z możliwością przeciążenia.Element access, such as a[x], is not considered an overloadable operator. Zamiast tego, zdefiniowane przez użytkownika indeksowanie jest obsługiwane za poorednictwem indeksatorów (indeksatorów).Instead, user-defined indexing is supported through indexers (Indexers).

W wyrażeniach operatory są wywoływane przy użyciu notacji operatora, a w deklaracjach operatory są odwoływane przy użyciu notacji funkcjonalnej.In expressions, operators are referenced using operator notation, and in declarations, operators are referenced using functional notation. W poniższej tabeli przedstawiono relacje między operatorami i notacjami funkcjonalnymi dla operatorów jednoargumentowych i binarnych.The following table shows the relationship between operator and functional notations for unary and binary operators. W pierwszym wpisie op oznacza każdy jednoargumentowy operator prefiksu z możliwością przeciążenia.In the first entry, op denotes any overloadable unary prefix operator. W drugim wpisie op oznacza jednoargumentowy przyrost ++ i operatory --.In the second entry, op denotes the unary postfix ++ and -- operators. W trzecim wpisie op oznacza dowolny operator binarny z możliwością przeciążenia.In the third entry, op denotes any overloadable binary operator.

Notacja operatoraOperator notation Notacja funkcjonalnaFunctional notation
op x operator op(x)
x op operator op(x)
x op y operator op(x,y)

Deklaracje operatora zdefiniowane przez użytkownika zawsze wymagają, aby co najmniej jeden z parametrów był klasą lub typem struktury, który zawiera deklarację operatora.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. Dlatego nie jest możliwe, aby operator zdefiniowany przez użytkownika miał taki sam podpis jak wstępnie zdefiniowany operator.Thus, it is not possible for a user-defined operator to have the same signature as a predefined operator.

Deklaracje operatora zdefiniowane przez użytkownika nie mogą modyfikować składni, pierwszeństwa ani łącznośći operatora.User-defined operator declarations cannot modify the syntax, precedence, or associativity of an operator. Na przykład operator / jest zawsze operatorem binarnym, zawsze ma poziom pierwszeństwa określony w priorytecie operatora i łączność, a zawsze jest w pełni skojarzony z lewej strony.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.

Chociaż jest możliwe, aby operator zdefiniowany przez użytkownika wykonywał jakiekolwiek obliczenia, należy zdecydowanie odradzać implementacje, które generują wyniki inne niż te, które są w sposób intuicyjny.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. Na przykład implementacja operator == powinna porównać dwa operandy dla równości i zwrócić odpowiedni booly wynik.For example, an implementation of operator == should compare the two operands for equality and return an appropriate bool result.

Opisy poszczególnych operatorów w wyrażeniach podstawowych za pomocą warunkowych operatorów logicznych określają wstępnie zdefiniowane implementacje operatorów i wszelkie dodatkowe reguły, które mają zastosowanie do każdego operatora.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. Opisy korzystają z warunków przeciążania przeciążenia operatora jednoargumentowego, rozpoznawania przeciążania operatora binarnegoi promocji liczbowych, definicji znalezionych w poniższych sekcjach.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.

Rozpoznanie przeciążenia operatora jednoargumentowegoUnary operator overload resolution

Operacja op x lub x op, gdzie op jest operatorem jednoargumentowym z możliwością przeciążenia, a x jest wyrażeniem typu X, jest przetwarzana w następujący sposób: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:

  • Zestaw operatorów zdefiniowanych przez użytkownika w X dla operacji operator op(x) jest określany przy użyciu reguł kandydujących operatorów zdefiniowanych przez użytkownika.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.
  • Jeśli zestaw operatorów zdefiniowanych przez użytkownika nie jest pusty, zostanie to zestaw operatorów kandydujących dla operacji.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. W przeciwnym razie wstępnie zdefiniowane jednoargumentowe implementacje operator op, w tym ich zniesione formularze, staną się zestawem operatorów kandydujących dla operacji.Otherwise, the predefined unary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. Wstępnie zdefiniowane implementacje danego operatora są określone w opisie operatora (wyrażenia podstawowe i operatory jednoargumentowe).The predefined implementations of a given operator are specified in the description of the operator (Primary expressions and Unary operators).
  • Reguły rozpoznawania przeciążenia są stosowane do zestawu operatorów kandydujących w celu wybrania najlepszego operatora w odniesieniu do listy argumentów (x), a ten operator będzie wynikiem procesu rozpoznawania przeciążenia.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. Jeśli nie można wybrać pojedynczego najlepszego operatora rozpoznawania przeciążenia, wystąpi błąd w czasie powiązania.If overload resolution fails to select a single best operator, a binding-time error occurs.

Rozpoznawanie przeciążenia operatora binarnegoBinary operator overload resolution

Operacja x op y, gdzie op jest operatorem binarnym przeciążania, x jest wyrażeniem typu X, a y jest wyrażeniem typu Y, jest przetwarzana w następujący sposób: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:

  • Zestaw operatorów zdefiniowanych przez użytkownika kandydujących zapewnianych przez X i Y dla operacji operator op(x,y) został określony.The set of candidate user-defined operators provided by X and Y for the operation operator op(x,y) is determined. Zestaw składa się z Unii operatorów kandydujących dostarczanych przez X i operatorów kandydujących dostarczonych przez Y, z których każdy określa użycie reguł kandydujących operatorów zdefiniowanych przez użytkownika.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. Jeśli X i Y są tego samego typu lub jeśli X i Y pochodzą od wspólnego typu podstawowego, współdzielone operatory kandydujące występują tylko w połączonym zestawie.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.
  • Jeśli zestaw operatorów zdefiniowanych przez użytkownika nie jest pusty, zostanie to zestaw operatorów kandydujących dla operacji.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. W przeciwnym razie wstępnie zdefiniowane implementacje operator op binarnych, w tym ich zniesione formularze, staną się zestawem operatorów kandydujących dla operacji.Otherwise, the predefined binary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. Wstępnie zdefiniowane implementacje danego operatora są określone w opisie operatora (Operatory arytmetyczne za pomocą warunkowych operatorów logicznych).The predefined implementations of a given operator are specified in the description of the operator (Arithmetic operators through Conditional logical operators). Dla wstępnie zdefiniowanych typów wyliczeniowych i delegatów jedynymi uznanymi operatorami są te zdefiniowane przez typ wyliczeniowy lub delegata, który jest typem czasu powiązania jednego z operandów.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.
  • Reguły rozpoznawania przeciążenia są stosowane do zestawu operatorów kandydujących w celu wybrania najlepszego operatora w odniesieniu do listy argumentów (x,y), a ten operator będzie wynikiem procesu rozpoznawania przeciążenia.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. Jeśli nie można wybrać pojedynczego najlepszego operatora rozpoznawania przeciążenia, wystąpi błąd w czasie powiązania.If overload resolution fails to select a single best operator, a binding-time error occurs.

Kandydujące Operatory zdefiniowane przez użytkownikaCandidate user-defined operators

Uwzględniając typ T i operator op(A)operacji, gdzie op jest operatorem przeciążania, a A jest listą argumentów, zestaw operatorów zdefiniowanych przez użytkownika w T dla operator op(A) jest określony w następujący sposób: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:

  • Określ typ T0.Determine the type T0. Jeśli T jest typem dopuszczającym wartość null, T0 jest jego typem podstawowym, w przeciwnym razie T0 jest równa T.If T is a nullable type, T0 is its underlying type, otherwise T0 is equal to T.
  • W przypadku wszystkich operator op deklaracji w T0 i wszystkich podnoszenia formularzy takich operatorów, jeśli ma zastosowanie co najmniej jednego operatora (odpowiedni element członkowski funkcji) w odniesieniu do listy argumentów A, a następnie zestaw operatorów kandydujących składa się ze wszystkich odpowiednich operatorów w 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.
  • W przeciwnym razie, jeśli T0 jest object, zestaw operatorów kandydujących jest pusty.Otherwise, if T0 is object, the set of candidate operators is empty.
  • W przeciwnym razie zestaw operatorów kandydujących udostępniany przez T0 jest zestawem operatorów kandydujących dostarczanych przez bezpośrednią klasę bazową T0lub obowiązującą klasą bazową T0 Jeśli T0 jest parametrem typu.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.

Promocje numeryczneNumeric promotions

Promocja liczbowa składa się z automatycznego wykonywania niektórych niejawnych konwersji argumentów operacji dla wstępnie zdefiniowanych jednoargumentowych i binarnych operatorów liczbowych.Numeric promotion consists of automatically performing certain implicit conversions of the operands of the predefined unary and binary numeric operators. Promocja numeryczna nie jest odrębnym mechanizmem, ale raczej efektem zastosowania rozpoznawania przeciążenia do wstępnie zdefiniowanych operatorów.Numeric promotion is not a distinct mechanism, but rather an effect of applying overload resolution to the predefined operators. Promocja liczbowa w specjalny sposób nie wpływa na ocenę operatorów zdefiniowanych przez użytkownika, chociaż Operatory zdefiniowane przez użytkownika mogą być implementowane w taki sposób, aby miały podobne skutki.Numeric promotion specifically does not affect evaluation of user-defined operators, although user-defined operators can be implemented to exhibit similar effects.

Przykładem promocji numerycznych jest rozważenie wstępnie zdefiniowanych implementacji operatora * binarnych: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);

Gdy reguły rozpoznawania przeciążenia (rozwiązanie przeciążenia) są stosowane do tego zestawu operatorów, efektem jest wybranie pierwszego z operatorów, dla których istnieją niejawne konwersje z typów operandów.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. Na przykład dla operacji b * s, gdzie b jest byte i s jest short, rozpoznawanie przeciążenia wybiera operator *(int,int) jako najlepszy operator.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. W związku z tym efektem jest to, że b i s są konwertowane na int, a typ wyniku jest int.Thus, the effect is that b and s are converted to int, and the type of the result is int. Podobnie w przypadku operacji i * d, gdzie i jest int i d jest double, rozpoznawanie przeciążenia wybiera operator *(double,double) jako najlepszy operator.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.

Jednoargumentowe promocje liczboweUnary numeric promotions

Jednoargumentowa promocja numeryczna występuje dla argumentów operacji wstępnie zdefiniowanych +, -i ~ operatory jednoargumentowe.Unary numeric promotion occurs for the operands of the predefined +, -, and ~ unary operators. Jednoargumentowa promocja liczbowa polega na przekonwertowaniu operandów typu sbyte, byte, short, ushortlub char do typu int.Unary numeric promotion simply consists of converting operands of type sbyte, byte, short, ushort, or char to type int. Ponadto dla jednoargumentowego operatora -, Jednoargumentowa promocja liczbowa konwertuje operandy typu uint do typu long.Additionally, for the unary - operator, unary numeric promotion converts operands of type uint to type long.

Binarne promocje liczboweBinary numeric promotions

Binarne promocję liczbową występuje w przypadku operandów wstępnie zdefiniowanych +, -, *, /, %, &, |, ^, ==, !=, >, <, >=, <= i operatorów binarnych.Binary numeric promotion occurs for the operands of the predefined +, -, *, /, %, &, |, ^, ==, !=, >, <, >=, and <= binary operators. Binarne promocję liczbową niejawnie konwertuje oba operandy na wspólny typ, który, w przypadku operatorów nierelacyjnych, również staje się typem wyniku operacji.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. Binarne promocje liczbowe polega na zastosowaniu następujących reguł w kolejności, w jakiej są wyświetlane w tym miejscu:Binary numeric promotion consists of applying the following rules, in the order they appear here:

  • Jeśli oba operandy są typu decimal, drugi operand jest konwertowany na typ decimallub wystąpi błąd w czasie powiązania, jeśli inny operand jest typu float lub 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.
  • W przeciwnym razie, jeśli jeden z operandów jest typu double, drugi operand jest konwertowany na typ double.Otherwise, if either operand is of type double, the other operand is converted to type double.
  • W przeciwnym razie, jeśli jeden z operandów jest typu float, drugi operand jest konwertowany na typ float.Otherwise, if either operand is of type float, the other operand is converted to type float.
  • W przeciwnym razie, jeśli jeden z operandów jest typu ulong, drugi operand jest konwertowany na typ ulonglub wystąpi błąd w czasie powiązania, jeśli inny operand jest typu sbyte, short, intlub 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.
  • W przeciwnym razie, jeśli jeden z operandów jest typu long, drugi operand jest konwertowany na typ long.Otherwise, if either operand is of type long, the other operand is converted to type long.
  • W przeciwnym razie, jeśli jeden z operandów jest typu uint, a drugi operand jest typu sbyte, shortlub int, oba operandy są konwertowane na typ 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.
  • W przeciwnym razie, jeśli jeden z operandów jest typu uint, drugi operand jest konwertowany na typ uint.Otherwise, if either operand is of type uint, the other operand is converted to type uint.
  • W przeciwnym razie oba operandy są konwertowane na typ int.Otherwise, both operands are converted to type int.

Należy zauważyć, że pierwsza reguła nie zezwala na wszystkie operacje, które mieszają typ decimal z typami double i float.Note that the first rule disallows any operations that mix the decimal type with the double and float types. Reguła wynika z faktu, że nie istnieją niejawne konwersje między typem decimal i double i float.The rule follows from the fact that there are no implicit conversions between the decimal type and the double and float types.

Należy również zauważyć, że nie jest możliwe, aby operand był typu ulong, gdy inny operand jest podpisanym typem całkowitym.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. Przyczyną jest brak typu całkowitego, który może reprezentować pełny zakres ulong, a także z podpisanymi typami całkowitymi.The reason is that no integral type exists that can represent the full range of ulong as well as the signed integral types.

W obu powyższych przypadkach wyrażenie cast może służyć do jawnej konwersji jednego operandu na typ, który jest zgodny z drugim operandem.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.

w przykładzieIn the example

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

Wystąpił błąd w czasie powiązania, ponieważ nie można pomnożyć decimal przez double.a binding-time error occurs because a decimal cannot be multiplied by a double. Błąd został rozwiązany przez jawne przekonwertowanie drugiego operandu na decimalw następujący sposób: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);
}

Podniesione operatoryLifted operators

Podnoszone operatory zezwalają wstępnie zdefiniowanym i zdefiniowanym przez użytkownika operatorom, którzy działają na typach wartości, które nie dopuszczają wartości null, również są używane z dopuszczaniem wartości null dla tych typów.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. Podnoszone operatory są zbudowane ze wstępnie zdefiniowanych i zdefiniowanych przez użytkownika operatorów spełniających określone wymagania, zgodnie z opisem w następujących tematach:Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:

  • Dla operatorów jednoargumentowychFor the unary operators

    +  ++  -  --  !  ~
    

    podnieśna postać operatora istnieje, jeśli argument operacji i typ wyniku nie dopuszcza wartości null.a lifted form of an operator exists if the operand and result types are both non-nullable value types. Unieś formularz jest konstruowany przez dodanie pojedynczego modyfikatora ? do operandu i typów wyników.The lifted form is constructed by adding a single ? modifier to the operand and result types. Podnieśny operator generuje wartość null, jeśli operand ma wartość null.The lifted operator produces a null value if the operand is null. W przeciwnym razie, podnieśny operator odwinie operand, stosuje operator podstawowy i otacza wynik.Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.

  • Dla operatorów binarnychFor the binary operators

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

    podnieśna postać operatora istnieje, jeśli operand i typy wyników to wszystkie wartości niedopuszczające wartości null.a lifted form of an operator exists if the operand and result types are all non-nullable value types. Unieś formularz jest konstruowany przez dodanie pojedynczego modyfikatora ? do każdego operandu i typu wyniku.The lifted form is constructed by adding a single ? modifier to each operand and result type. Podnieśny operator generuje wartość null, jeśli jeden lub oba operandy mają wartość null (wyjątek & i | operatory typu bool?, zgodnie z opisem w operatorach logicznych logicznej).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). W przeciwnym razie podnieśny operator odpakuje operandy, zastosuje operator podstawowy i otacza wynik.Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.

  • Dla operatorów równościFor the equality operators

    ==  !=
    

    podnieśna postać operatora istnieje, jeśli typy operandów to zarówno typ wartości niedopuszczający wartości null, jak i typ wyniku 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. Zniesiony formularz jest konstruowany przez dodanie pojedynczego modyfikatora ? do każdego typu operandu.The lifted form is constructed by adding a single ? modifier to each operand type. Podnieśny operator traktuje dwie wartości null, a wartość null nie jest równa żadnej wartości innej niż null.The lifted operator considers two null values equal, and a null value unequal to any non-null value. Jeśli oba operandy mają wartość różną od null, przenoszonego operatora odwinie operandy i zastosuje operatora bazowego, aby wygenerować wynik bool.If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

  • Dla operatorów relacyjnychFor the relational operators

    <  >  <=  >=
    

    podnieśna postać operatora istnieje, jeśli typy operandów to zarówno typ wartości niedopuszczający wartości null, jak i typ wyniku 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. Zniesiony formularz jest konstruowany przez dodanie pojedynczego modyfikatora ? do każdego typu operandu.The lifted form is constructed by adding a single ? modifier to each operand type. Podnieśny operator tworzy wartość false, jeśli jeden lub oba operandy mają wartość null.The lifted operator produces the value false if one or both operands are null. W przeciwnym razie podnieśny operator odwinie operandy i zastosuje operatora bazowego, aby wygenerować wynik bool.Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

Wyszukiwanie elementów członkowskichMember lookup

Przeszukiwanie elementu członkowskiego jest procesem, w którym określa się znaczenie nazwy w kontekście typu.A member lookup is the process whereby the meaning of a name in the context of a type is determined. Wyszukiwanie elementu członkowskiego może odbywać się w ramach oceny simple_name (prostych nazw) lub member_access (dostęp do elementu członkowskiego) w wyrażeniu.A member lookup can occur as part of evaluating a simple_name (Simple names) or a member_access (Member access) in an expression. Jeśli simple_name lub member_access występuje jako primary_expression invocation_expression (wywołania metody), element członkowski jest określany jako wywoływany.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.

Jeśli element członkowski jest metodą lub zdarzeniem lub jeśli jest to stała, pole lub właściwość typu delegata (delegatów) lub typu dynamic (Typ dynamiczny), wówczas element członkowski jest określany jako wywoływać.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.

Funkcja wyszukiwania elementów członkowskich traktuje nie tylko nazwę elementu członkowskiego, ale również liczbę parametrów typu, które ma element członkowski i czy element członkowski jest dostępny.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. Na potrzeby wyszukiwania elementów członkowskich, metod ogólnych i zagnieżdżonych typów ogólnych ma liczbę parametrów typu wskazanych w odpowiednich deklaracjach, a wszystkie inne elementy członkowskie mają parametry typu zero.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.

Przeszukiwanie elementu członkowskiego o nazwie N z parametrami typu K w T jest przetwarzane w następujący sposób:A member lookup of a name N with K type parameters in a type T is processed as follows:

  • Najpierw zostanie wyznaczona zbiór dostępnych składowych o nazwie N:First, a set of accessible members named N is determined:
    • Jeśli T jest parametrem typu, zestaw jest Unią zestawów dostępnych składowych o nazwie N w każdym typie określonym jako ograniczenie podstawowe lub ograniczenie pomocnicze (ograniczenia parametru typu) dla Toraz zestaw dostępnych elementów członkowskich o nazwie N w 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.
    • W przeciwnym razie zestaw składa się ze wszystkich dostępnych członków (dostęp członków) o nazwie NT, łącznie z dziedziczonymi członkami i dostępnymi elementami członkowskimi o nazwie N w 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. Jeśli T jest typem skonstruowanym, zestaw elementów członkowskich jest uzyskiwany przez podstawianie argumentów typu, zgodnie z opisem w składowych typów skonstruowanych.If T is a constructed type, the set of members is obtained by substituting type arguments as described in Members of constructed types. Elementy członkowskie, które zawierają modyfikator override, są wykluczone z zestawu.Members that include an override modifier are excluded from the set.
  • Następnie Jeśli K ma wartość zero, wszystkie typy zagnieżdżone, których deklaracje obejmują parametry typu, są usuwane.Next, if K is zero, all nested types whose declarations include type parameters are removed. Jeśli K nie jest zerem, wszystkie elementy członkowskie z inną liczbą parametrów typu są usuwane.If K is not zero, all members with a different number of type parameters are removed. Należy pamiętać, że jeśli K ma wartość zero, metody mające parametry typu nie zostaną usunięte, ponieważ proces wnioskowania typów (wnioskowanieo typie) może być w stanie wywnioskować argumenty typu.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.
  • Następnie, jeśli element członkowski jest wywoływany, wszystkie elementy członkowskie inne niżwywoływać są usuwane z zestawu.Next, if the member is invoked, all non-invocable members are removed from the set.
  • Następnie elementy członkowskie, które są ukryte przez inne elementy członkowskie, są usuwane z zestawu.Next, members that are hidden by other members are removed from the set. Dla każdego elementu członkowskiego S.M w zestawie, gdzie S jest typem, w którym zadeklarowany jest M elementu członkowskiego, są stosowane następujące reguły: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:
    • Jeśli M to stała, pole, właściwość, zdarzenie lub element członkowski wyliczenia, wszystkie elementy członkowskie zadeklarowane w typie podstawowym S są usuwane z zestawu.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.
    • Jeśli M jest deklaracją typu, wszystkie typy, które nie są zadeklarowane w typie podstawowym S, są usuwane z zestawu, a wszystkie deklaracje typu z tą samą liczbą parametrów typu jako M zadeklarowane w typie podstawowym S są usuwane z zestawu.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.
    • Jeśli M jest metodą, wszystkie elementy członkowskie inne niż metody zadeklarowane w typie podstawowym S są usuwane z zestawu.If M is a method, then all non-method members declared in a base type of S are removed from the set.
  • Następnie elementy członkowskie interfejsu, które są ukryte przez elementy członkowskie klasy, są usuwane z zestawu.Next, interface members that are hidden by class members are removed from the set. Ten krok ma wpływ tylko wtedy, gdy T jest parametrem typu, a T ma zarówno obowiązującą klasę bazową inną niż object, jak i niepusty obowiązujący zestaw interfejsów (ograniczenia parametru typu).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). Dla każdego elementu członkowskiego S.M w zestawie, gdzie S jest typem, w którym zadeklarowany jest M elementu członkowskiego, są stosowane następujące reguły, jeśli S jest deklaracją klasy inną niż 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:
    • Jeśli M jest stałą, pole, właściwość, zdarzenie, element członkowski wyliczenia lub Deklaracja typu, wszystkie elementy członkowskie zadeklarowane w deklaracji interfejsu są usuwane z zestawu.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.
    • Jeśli M jest metodą, wszystkie elementy członkowskie inne niż metody zadeklarowane w deklaracji interfejsu są usuwane z zestawu, a wszystkie metody z tą samą sygnaturą co M zadeklarowane w deklaracji interfejsu są usuwane z zestawu.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.
  • Na koniec po usunięciu ukrytych elementów członkowskich zostanie określony wynik wyszukiwania:Finally, having removed hidden members, the result of the lookup is determined:
    • Jeśli zestaw składa się z pojedynczego elementu członkowskiego, który nie jest metodą, wówczas ten element członkowski jest wynikiem wyszukiwania.If the set consists of a single member that is not a method, then this member is the result of the lookup.
    • W przeciwnym razie, jeśli zestaw zawiera tylko metody, ta grupa metod jest wynikiem wyszukiwania.Otherwise, if the set contains only methods, then this group of methods is the result of the lookup.
    • W przeciwnym razie odnośnik jest niejednoznaczny i wystąpi błąd w czasie powiązania.Otherwise, the lookup is ambiguous, and a binding-time error occurs.

W przypadku przeszukiwania elementów członkowskich w typach innych niż parametry typu i interfejsy oraz wyszukiwania elementów członkowskich w interfejsach, które są ściśle dziedziczenia (każdy interfejs w łańcuchu dziedziczenia ma dokładnie zero lub jeden bezpośredni interfejs podstawowy), efekt reguł wyszukiwania to Wystarczy, że pochodni członkowie ukrywają elementy bazowe o tej samej nazwie lub podpisie.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. Takie wyszukiwania o pojedynczej dziedziczeniu nigdy nie są niejednoznaczne.Such single-inheritance lookups are never ambiguous. Niejasności, które mogą wystąpić w odnośnikach elementów członkowskich w interfejsach z wieloma dziedziczeniem, są opisane w dostęp do elementu członkowskiego interfejsu.The ambiguities that can possibly arise from member lookups in multiple-inheritance interfaces are described in Interface member access.

Typy podstawoweBase types

W celach wyszukiwania elementów członkowskich typ T jest traktowany jako mający następujące typy podstawowe:For purposes of member lookup, a type T is considered to have the following base types:

  • Jeśli T jest object, T nie ma typu podstawowego.If T is object, then T has no base type.
  • Jeśli T jest enum_type, typy podstawowe T są typami klas System.Enum, System.ValueTypei object.If T is an enum_type, the base types of T are the class types System.Enum, System.ValueType, and object.
  • Jeśli T jest struct_type, typy podstawowe T są typami klas System.ValueType i object.If T is a struct_type, the base types of T are the class types System.ValueType and object.
  • Jeśli T jest class_type, podstawowe typy T są klasami podstawowymi T, łącznie z typem klasy object.If T is a class_type, the base types of T are the base classes of T, including the class type object.
  • Jeśli T jest INTERFACE_TYPE, podstawowe typy T są podstawowymi interfejsami T i typem klasy object.If T is an interface_type, the base types of T are the base interfaces of T and the class type object.
  • Jeśli T jest array_type, typy podstawowe T są typami klas System.Array i object.If T is an array_type, the base types of T are the class types System.Array and object.
  • Jeśli T jest delegate_type, typy podstawowe T są typami klas System.Delegate i object.If T is a delegate_type, the base types of T are the class types System.Delegate and object.

Elementy członkowskie funkcjiFunction members

Składowe funkcji są elementami członkowskimi, które zawierają instrukcje wykonywalne.Function members are members that contain executable statements. Składowe funkcji są zawsze członkami typów i nie mogą być elementami członkowskimi przestrzeni nazw.Function members are always members of types and cannot be members of namespaces. C#definiuje następujące kategorie elementów członkowskich funkcji:C# defines the following categories of function members:

  • MetodyMethods
  • WłaściwościProperties
  • ZdarzeniaEvents
  • IndeksatoryIndexers
  • Operatory zdefiniowane przez użytkownikaUser-defined operators
  • Konstruktory wystąpieńInstance constructors
  • Konstruktory statyczneStatic constructors
  • DestruktoryDestructors

Oprócz destruktorów i konstruktorów statycznych (które nie mogą być wywoływane jawnie), instrukcje zawarte w składowych funkcji są wykonywane za pomocą wywołań elementu członkowskiego funkcji.Except for destructors and static constructors (which cannot be invoked explicitly), the statements contained in function members are executed through function member invocations. Rzeczywista składnia do pisania wywołania składowej funkcji zależy od określonej kategorii elementu członkowskiego funkcji.The actual syntax for writing a function member invocation depends on the particular function member category.

Lista argumentów (listy argumentów) wywołania elementu członkowskiego funkcji udostępnia wartości rzeczywiste lub odwołania do zmiennych dla parametrów elementu członkowskiego funkcji.The argument list (Argument lists) of a function member invocation provides actual values or variable references for the parameters of the function member.

Wywołania metod ogólnych mogą wykorzystywać wnioskowanie o typie w celu określenia zestawu argumentów typu, które mają zostać przekazane do metody.Invocations of generic methods may employ type inference to determine the set of type arguments to pass to the method. Ten proces jest opisany w wnioskach o typie.This process is described in Type inference.

Wywołania metod, indeksatorów, operatorów i wystąpień stosują rozwiązanie przeciążenia, aby określić, który zestaw elementów członkowskich funkcji ma być wywoływany.Invocations of methods, indexers, operators and instance constructors employ overload resolution to determine which of a candidate set of function members to invoke. Ten proces jest opisany w temacie rozpoznawanie przeciążenia.This process is described in Overload resolution.

Gdy określony element członkowski funkcji zostanie zidentyfikowany w czasie wiązania, prawdopodobnie przez rozpoznanie przeciążenia, rzeczywisty proces wykonywania wywoływany przez element członkowski funkcji jest opisany w kontroli w czasie kompilacji dynamicznego rozpoznawania przeciążenia.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.

Poniższa tabela zawiera podsumowanie przetwarzania, które odbywa się w konstrukcjach obejmujących sześć kategorii elementów członkowskich funkcji, które można jawnie wywołać.The following table summarizes the processing that takes place in constructs involving the six categories of function members that can be explicitly invoked. W tabeli, e, x, yi value wskazują wyrażenia sklasyfikowane jako zmienne lub wartości, T wskazuje wyrażenie sklasyfikowane jako typ, F jest prostą nazwą metody, a P jest prostą nazwą właściwości.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.

ConstructConstruct PrzykładExample OpisDescription
Wywołanie metodyMethod invocation F(x,y) Rozpoznanie przeciążenia jest stosowane w celu wybrania najlepszej metody F w zawierającej ją klasie lub strukturze.Overload resolution is applied to select the best method F in the containing class or struct. Metoda jest wywoływana z listą argumentów (x,y).The method is invoked with the argument list (x,y). Jeśli metoda nie jest static, wyrażenie wystąpienia jest this.If the method is not static, the instance expression is this.
T.F(x,y) Rozpoznanie przeciążenia jest stosowane do wybierania najlepszej metody F w klasie lub strukturze T.Overload resolution is applied to select the best method F in the class or struct T. Błąd czasu powiązania występuje, jeśli metoda nie jest static.A binding-time error occurs if the method is not static. Metoda jest wywoływana z listą argumentów (x,y).The method is invoked with the argument list (x,y).
e.F(x,y) Rozpoznanie przeciążenia jest stosowane w celu wybrania najlepszej metody F w klasie, strukturze lub interfejsie określonej przez typ e.Overload resolution is applied to select the best method F in the class, struct, or interface given by the type of e. Jeśli metoda jest static, występuje błąd czasu powiązania.A binding-time error occurs if the method is static. Metoda jest wywoływana z wyrażeniem wystąpienia e i listą argumentów (x,y).The method is invoked with the instance expression e and the argument list (x,y).
Dostęp do właściwościProperty access P Zostanie wywołana metoda dostępu get P właściwości w zawierającej ją klasie lub strukturze.The get accessor of the property P in the containing class or struct is invoked. Błąd czasu kompilacji występuje, jeśli P jest tylko do zapisu.A compile-time error occurs if P is write-only. Jeśli P nie jest static, wyrażenie wystąpienia jest this.If P is not static, the instance expression is this.
P = value Metoda dostępu set P właściwości w zawartej klasie lub strukturze jest wywoływana z listą argumentów (value).The set accessor of the property P in the containing class or struct is invoked with the argument list (value). Błąd czasu kompilacji występuje, jeśli P jest tylko do odczytu.A compile-time error occurs if P is read-only. Jeśli P nie jest static, wyrażenie wystąpienia jest this.If P is not static, the instance expression is this.
T.P Metoda dostępu get P właściwości w klasie lub strukturze T jest wywoływana.The get accessor of the property P in the class or struct T is invoked. Błąd czasu kompilacji występuje, jeśli P nie static lub jeśli P jest tylko do zapisu.A compile-time error occurs if P is not static or if P is write-only.
T.P = value Metoda dostępu set P właściwości w klasie lub strukturze T jest wywoływana z listą argumentów (value).The set accessor of the property P in the class or struct T is invoked with the argument list (value). Błąd czasu kompilacji występuje, jeśli P nie static lub jeśli P jest tylko do odczytu.A compile-time error occurs if P is not static or if P is read-only.
e.P Metoda dostępu get P właściwości w klasie, strukturze lub interfejsie określona przez typ e jest wywoływana z wyrażeniem wystąpienia 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. Błąd czasu powiązania występuje, jeśli P jest static lub jeśli P jest tylko do zapisu.A binding-time error occurs if P is static or if P is write-only.
e.P = value Metoda dostępu set P właściwości w klasie, strukturze lub interfejsie określona przez typ e jest wywoływana przy użyciu wyrażenia wystąpienia e i listy argumentów (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). Błąd czasu powiązania występuje, jeśli P jest static lub jeśli P jest tylko do odczytu.A binding-time error occurs if P is static or if P is read-only.
Dostęp do zdarzeńEvent access E += value Metoda dostępu add E zdarzeń w klasie lub strukturze zawierającej jest wywoływana.The add accessor of the event E in the containing class or struct is invoked. Jeśli E nie jest statyczna, wyrażenie wystąpienia jest this.If E is not static, the instance expression is this.
E -= value Metoda dostępu remove E zdarzeń w klasie lub strukturze zawierającej jest wywoływana.The remove accessor of the event E in the containing class or struct is invoked. Jeśli E nie jest statyczna, wyrażenie wystąpienia jest this.If E is not static, the instance expression is this.
T.E += value Metoda dostępu add E zdarzeń w klasie lub strukturze T jest wywoływana.The add accessor of the event E in the class or struct T is invoked. Jeśli E nie jest statyczna, występuje błąd czasu powiązania.A binding-time error occurs if E is not static.
T.E -= value Metoda dostępu remove E zdarzeń w klasie lub strukturze T jest wywoływana.The remove accessor of the event E in the class or struct T is invoked. Jeśli E nie jest statyczna, występuje błąd czasu powiązania.A binding-time error occurs if E is not static.
e.E += value Metoda dostępu add E zdarzeń w klasie, strukturze lub interfejsie określona przez typ e jest wywoływana z wyrażeniem wystąpienia 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. Gdy E jest statyczny, występuje błąd czasu powiązania.A binding-time error occurs if E is static.
e.E -= value Metoda dostępu remove E zdarzeń w klasie, strukturze lub interfejsie określona przez typ e jest wywoływana z wyrażeniem wystąpienia 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. Gdy E jest statyczny, występuje błąd czasu powiązania.A binding-time error occurs if E is static.
Dostęp indeksatoraIndexer access e[x,y] Rozpoznanie przeciążenia jest stosowane w celu wybrania najlepszego indeksatora w klasie, strukturze lub interfejsie przyznanym przez typ e.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. Metoda dostępu get indeksatora jest wywoływana z wyrażeniem wystąpienia e i listą argumentów (x,y).The get accessor of the indexer is invoked with the instance expression e and the argument list (x,y). Błąd czasu powiązania występuje, gdy indeksator jest tylko do zapisu.A binding-time error occurs if the indexer is write-only.
e[x,y] = value Rozpoznanie przeciążenia jest stosowane w celu wybrania najlepszego indeksatora w klasie, strukturze lub interfejsie przyznanym przez typ e.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. Metoda dostępu set indeksatora jest wywoływana z wyrażeniem wystąpienia e i listą argumentów (x,y,value).The set accessor of the indexer is invoked with the instance expression e and the argument list (x,y,value). Błąd czasu powiązania występuje, gdy indeksator jest tylko do odczytu.A binding-time error occurs if the indexer is read-only.
Wywołanie operatoraOperator invocation -x Rozpoznanie przeciążenia jest stosowane w celu wybrania najlepszego operatora jednoargumentowego w klasie lub strukturze podanej przez typ x.Overload resolution is applied to select the best unary operator in the class or struct given by the type of x. Wybrany operator jest wywoływany z listą argumentów (x).The selected operator is invoked with the argument list (x).
x + y Rozpoznanie przeciążenia jest stosowane w celu wybrania najlepszego operatora binarnego w klasach lub strukturach określonych przez typy x i y.Overload resolution is applied to select the best binary operator in the classes or structs given by the types of x and y. Wybrany operator jest wywoływany z listą argumentów (x,y).The selected operator is invoked with the argument list (x,y).
Wywołanie konstruktora wystąpieniaInstance constructor invocation new T(x,y) Rozpoznanie przeciążenia jest stosowane do wybierania najlepszego konstruktora wystąpienia w klasie lub strukturze T.Overload resolution is applied to select the best instance constructor in the class or struct T. Konstruktor wystąpienia jest wywoływany z listą argumentów (x,y).The instance constructor is invoked with the argument list (x,y).

Listy argumentówArgument lists

Każdy element członkowski funkcji i obiekt delegowany zawiera listę argumentów, która dostarcza wartości rzeczywiste lub odwołania do zmiennych parametrów elementu członkowskiego funkcji.Every function member and delegate invocation includes an argument list which provides actual values or variable references for the parameters of the function member. Składnia określająca listę argumentów wywołania elementu członkowskiego funkcji zależy od kategorii elementu członkowskiego funkcji:The syntax for specifying the argument list of a function member invocation depends on the function member category:

  • W przypadku konstruktorów wystąpień, metod, indeksatorów i delegatów argumenty są określone jako argument_list, zgodnie z poniższym opisem.For instance constructors, methods, indexers and delegates, the arguments are specified as an argument_list, as described below. W przypadku indeksatorów podczas wywoływania metody dostępu set, lista argumentów dodatkowo zawiera wyrażenie określone jako prawy operand operatora przypisania.For indexers, when invoking the set accessor, the argument list additionally includes the expression specified as the right operand of the assignment operator.
  • Dla właściwości, lista argumentów jest pusta podczas wywoływania metody dostępu get i składa się z wyrażenia określonego jako prawy operand operatora przypisania podczas wywoływania metody dostępu 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.
  • Dla zdarzeń lista argumentów składa się z wyrażenia określonego jako prawy operand operatora += lub -=.For events, the argument list consists of the expression specified as the right operand of the += or -= operator.
  • Dla operatorów zdefiniowanych przez użytkownika lista argumentów składa się z pojedynczego operandu jednoargumentowego operatora lub dwóch operandów operatora binarnego.For user-defined operators, the argument list consists of the single operand of the unary operator or the two operands of the binary operator.

Argumenty właściwości (Właściwości), zdarzenia (zdarzenia) i Operatory zdefiniowane przez użytkownika (Operatory) są zawsze przekazane jako parametry wartości (Parametry wartości).The arguments of properties (Properties), events (Events), and user-defined operators (Operators) are always passed as value parameters (Value parameters). Argumenty indeksatorów (indeksatorów) są zawsze przekazane jako parametry wartości (Parametry wartości) lub tablice parametrów (tablice parametrów).The arguments of indexers (Indexers) are always passed as value parameters (Value parameters) or parameter arrays (Parameter arrays). Parametry referencyjne i wyjściowe nie są obsługiwane dla tych kategorii elementów członkowskich funkcji.Reference and output parameters are not supported for these categories of function members.

Argumenty konstruktora wystąpienia, metody, indeksatora lub wywołania delegata są określone jako 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 składa się z jednego lub więcej argumentóws, rozdzielonych przecinkami.An argument_list consists of one or more arguments, separated by commas. Każdy argument składa się z opcjonalnego argument_name , po którym następuje argument_value.Each argument consists of an optional argument_name followed by an argument_value. Argument o argument_name jest określany jako argument nazwany, podczas gdy Argument bez argument_name jest argumentem pozycyjnym.An argument with an argument_name is referred to as a named argument, whereas an argument without an argument_name is a positional argument. Występuje błąd dla argumentu pozycyjnego, który ma być wyświetlany po nazwanym argumencie w argument_list.It is an error for a positional argument to appear after a named argument in an argument_list.

Argument_value może przyjmować jedną z następujących form:The argument_value can take one of the following forms:

  • Wyrażeniewskazujące, że argument jest przenoszona jako parametr wartości (Parametry wartości).An expression, indicating that the argument is passed as a value parameter (Value parameters).
  • Słowo kluczowe ref następuje variable_reference (odwołania do zmiennych) wskazujące, że argument jest przenoszona jako parametr odwołania (parametry odwołania).The keyword ref followed by a variable_reference (Variable references), indicating that the argument is passed as a reference parameter (Reference parameters). Zmienna musi być ostatecznie przypisana (przypisanie), zanim będzie mogła zostać przeniesiona jako parametr odwołania.A variable must be definitely assigned (Definite assignment) before it can be passed as a reference parameter. Słowo kluczowe out następuje variable_reference (odwołania do zmiennych), wskazujące, że argument jest przekazywane jako parametr wyjściowy (Parametry wyjściowe).The keyword out followed by a variable_reference (Variable references), indicating that the argument is passed as an output parameter (Output parameters). Zmienna jest uznawana za ostatecznie przypisaną (przypisanie) po wywołaniu elementu członkowskiego, w którym zmienna jest przenoszona jako parametr wyjściowy.A variable is considered definitely assigned (Definite assignment) following a function member invocation in which the variable is passed as an output parameter.

Odpowiednie parametryCorresponding parameters

Dla każdego argumentu na liście argumentów musi istnieć odpowiedni parametr w elemencie członkowskim funkcji lub w wywołaniu delegowania.For each argument in an argument list there has to be a corresponding parameter in the function member or delegate being invoked.

Lista parametrów użyta w poniższym przykładzie jest określona w następujący sposób:The parameter list used in the following is determined as follows:

  • W przypadku metod wirtualnych i indeksatorów zdefiniowanych w klasach lista parametrów jest wybierana z najbardziej szczegółowej deklaracji lub przesłonięcia składowej funkcji, rozpoczynając od typu statycznego odbiornika i przeszukiwania przez klasy bazowe.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.
  • W przypadku metod interfejsu i indeksatorów lista parametrów jest wybierana jako najbardziej Szczegółowa definicja elementu członkowskiego, rozpoczynając od typu interfejsu i przeszukiwaniem przez interfejsy podstawowe.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. Jeśli nie zostanie znaleziona lista parametrów unikatowych, jest to lista parametrów z niedostępnymi nazwami i żadne parametry opcjonalne nie są konstruowane, dlatego wywołania nie mogą używać parametrów nazwanych ani pomijać opcjonalnych argumentów.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.
  • Dla metod częściowych jest używana lista parametrów definiująca Deklaracja metody częściowej.For partial methods, the parameter list of the defining partial method declaration is used.
  • Dla wszystkich innych elementów członkowskich funkcji i delegatów istnieje tylko jedna lista parametrów, która jest używana.For all other function members and delegates there is only a single parameter list, which is the one used.

Pozycja argumentu lub parametru jest definiowana jako liczba argumentów lub parametrów poprzedzających je na liście argumentów lub liście parametrów.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.

Odpowiednie parametry argumentów elementu członkowskiego funkcji są określane w następujący sposób:The corresponding parameters for function member arguments are established as follows:

  • Argumenty w argument_list konstruktorów wystąpień, metodach, indeksatorach i delegatów:Arguments in the argument_list of instance constructors, methods, indexers and delegates:
    • Argument pozycyjny, gdzie stały parametr występuje w tym samym położeniu na liście parametrów odpowiada temu parametrowi.A positional argument where a fixed parameter occurs at the same position in the parameter list corresponds to that parameter.
    • Argument pozycyjny składowej funkcji z tablicą parametrów wywoływaną w jej normalnej postaci odpowiada tablicy parametrów, która musi występować w tym samym położeniu na liście parametrów.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.
    • Argument pozycyjny elementu członkowskiego funkcji z tablicą parametrów wywołaną w jego rozwiniętej postaci, gdzie żaden stały parametr nie występuje w tym samym położeniu na liście parametrów, odnosi się do elementu w tablicy parametrów.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.
    • Nazwany argument odpowiada parametrowi o tej samej nazwie na liście parametrów.A named argument corresponds to the parameter of the same name in the parameter list.
    • W przypadku indeksatorów podczas wywoływania metody dostępu set wyrażenie określone jako prawy operand operatora przypisania odpowiada parametrowi niejawnemu value deklaracji akcesora 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.
  • W przypadku właściwości podczas wywoływania metody dostępu get nie ma argumentów.For properties, when invoking the get accessor there are no arguments. Podczas wywoływania metody dostępu set, wyrażenie określone jako prawy operand operatora przypisania odpowiada parametrowi niejawnemu value deklaracji metody dostępu 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.
  • Dla operatorów jednoargumentowych zdefiniowanych przez użytkownika (w tym konwersji) pojedynczy operand odpowiada jednemu parametrowi deklaracji operatora.For user-defined unary operators (including conversions), the single operand corresponds to the single parameter of the operator declaration.
  • W przypadku operatorów binarnych zdefiniowanych przez użytkownika lewy argument operacji odpowiada pierwszemu parametrowi, a prawy operand odpowiada drugiemu parametrowi deklaracji operatora.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.

Ocena czasu wykonywania dla list argumentówRun-time evaluation of argument lists

W czasie wykonywania wywołania elementu członkowskiego funkcji (Sprawdzanie w czasie kompilacji dynamicznego rozpoznawania przeciążenia) wyrażenia lub odwołania do zmiennych listy argumentów są oceniane w kolejności od lewej do prawej w następujący sposób: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:

  • W przypadku parametru wartości wyrażenie argumentu jest oceniane i niejawna konwersja (niejawne konwersje) do odpowiedniego typu parametru.For a value parameter, the argument expression is evaluated and an implicit conversion (Implicit conversions) to the corresponding parameter type is performed. Wartość będąca wynikiem jest wartością początkową parametru value w wywołaniu elementu członkowskiego funkcji.The resulting value becomes the initial value of the value parameter in the function member invocation.
  • Dla parametru reference lub Output jest oceniane odwołanie do zmiennej, a wynikowa lokalizacja magazynu stanowi lokalizację magazynu reprezentowanego przez parametr w wywołaniu elementu członkowskiego funkcji.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. Jeśli odwołanie do zmiennej określone jako parametr Reference lub Output jest elementem tablicy reference_type, wykonywane jest sprawdzanie w czasie wykonywania, aby upewnić się, że typ elementu tablicy jest identyczny z typem parametru.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. Jeśli to sprawdzenie nie powiedzie się, zostanie zgłoszony System.ArrayTypeMismatchException.If this check fails, a System.ArrayTypeMismatchException is thrown.

Metody, indeksatory i konstruktory wystąpień mogą deklarować jako tablicę parametrów (tablice parametrów).Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter array (Parameter arrays). Takie składowe funkcji są wywoływane w ich normalnej formie lub w rozwiniętej formie, w zależności od tego, który ma zastosowanie (odpowiedni element członkowski funkcji):Such function members are invoked either in their normal form or in their expanded form depending on which is applicable (Applicable function member):

  • Gdy element członkowski funkcji z tablicą parametrów jest wywoływany w jego normalnej postaci, argument określony dla tablicy parametrów musi być pojedynczym wyrażeniem, które jest niejawnie konwertowane (konwersje niejawne) na typ tablicy parametrów.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. W takim przypadku tablica parametrów działa dokładnie tak, jak parametr value.In this case, the parameter array acts precisely like a value parameter.
  • Gdy element członkowski funkcji z tablicą parametrów jest wywoływany w jego rozwiniętej postaci, wywołanie musi określać zero lub więcej argumentów pozycyjnych dla tablicy parametrów, gdzie każdy argument jest wyrażeniem, które jest niejawnie konwertowane (konwersje niejawne) na typ elementu tablicy parametrów.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. W takim przypadku wywołanie tworzy wystąpienie typu tablicy parametrów o długości odpowiadającej liczbie argumentów, inicjuje elementy instancji Array z podaną wartością argumentów i używa nowo utworzonego wystąpienia tablicy jako wartości rzeczywistej argument.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.

Wyrażenia listy argumentów są zawsze oceniane w kolejności, w jakiej zostały wpisane.The expressions of an argument list are always evaluated in the order they are written. W tym przykładzie przykładThus, 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++);
    }
}

tworzy dane wyjścioweproduces the output

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

Reguły współwariancji tablicy (Kowariancja tablicowa) zezwalają na wartość typu tablicy A[] być odwołaniem do wystąpienia typu tablicy B[], pod warunkiem, że istnieje niejawna konwersja odwołań z B do 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. Ze względu na te reguły, gdy element tablicy reference_type jest przenoszona jako parametr Reference lub Output, wymagane jest sprawdzenie w czasie wykonywania, aby upewnić się, że rzeczywisty typ elementu tablicy jest identyczny z parametrem.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. w przykładzieIn 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
    }
}

drugie wywołanie F powoduje wygenerowanie System.ArrayTypeMismatchException, ponieważ rzeczywisty typ elementu b jest string i nie 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.

Gdy element członkowski funkcji z tablicą parametrów jest wywoływany w rozwiniętej postaci, wywołanie jest przetwarzane dokładnie tak, jakby wyrażenie tworzenia tablicy z inicjatorem tablicy (wyrażenia tworzenia tablicy) zostało wstawione wokół rozwiniętych parametrów.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. Na przykład, dana deklaracjaFor example, given the declaration

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

następujące wywołania rozwiniętej formy metodythe following invocations of the expanded form of the method

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

odpowiada dokładnie nacorrespond exactly to

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

W szczególności należy zauważyć, że pusta tablica jest tworzona, gdy dla tablicy parametrów nie podano żadnych argumentów.In particular, note that an empty array is created when there are zero arguments given for the parameter array.

Gdy argumenty są pomijane z elementu członkowskiego funkcji z odpowiednimi parametrami opcjonalnymi, domyślne argumenty deklaracji elementu członkowskiego funkcji są niejawnie przekazane.When arguments are omitted from a function member with corresponding optional parameters, the default arguments of the function member declaration are implicitly passed. Ponieważ są one zawsze stałe, ich ocena nie będzie miała wpływu na kolejność oceny pozostałych argumentów.Because these are always constant, their evaluation will not impact the evaluation order of the remaining arguments.

Wnioskowanie o typieType inference

Gdy metoda ogólna jest wywoływana bez określenia argumentów typu, proces wnioskowania o typie próbuje wnioskować o argumenty typu dla wywołania.When a generic method is called without specifying type arguments, a type inference process attempts to infer type arguments for the call. Obecność wnioskowania o typie umożliwia bardziej wygodną składnię do wywoływania metody ogólnej i umożliwia programisty uniknięcie określania nadmiarowych informacji o typie.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. Na przykład, dana Deklaracja metody: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;
    }
}

możliwe jest wywołanie metody Choose bez jawnego określenia argumentu typu: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>

Za pomocą wnioskowania o typie argumenty typu int i string są określane na podstawie argumentów metody.Through type inference, the type arguments int and string are determined from the arguments to the method.

Wnioskowanie o typie odbywa się w ramach przetwarzania powiązań metody wywołań metod (wywołań metod) i jest wykonywana przed etapem rozwiązywania przeciążenia wywołania.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. Gdy dana grupa metod jest określona w wywołaniu metody, a żadne argumenty typu nie są określone jako część wywołania metody, wnioskowanie typu jest stosowane do każdej metody ogólnej w grupie metod.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. Jeśli wnioskowanie o typie powiedzie się, argumenty typu wywnioskowanego są używane do określenia typów argumentów dla kolejnego rozwiązania przeciążenia.If type inference succeeds, then the inferred type arguments are used to determine the types of arguments for subsequent overload resolution. Jeśli rozwiązanie przeciążenia wybiera metodę rodzajową jako jedną do wywołania, wówczas argumenty typu wywnioskowanego są używane jako argumenty typu dla wywołania.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. Jeśli wnioskowanie o typie dla określonej metody nie powiedzie się, ta metoda nie bierze udziału w rozpoznawaniu przeciążenia.If type inference for a particular method fails, that method does not participate in overload resolution. Błąd wnioskowania o typie, w obu przypadkach nie powoduje błędu powiązania.The failure of type inference, in and of itself, does not cause a binding-time error. Jednak często prowadzi do błędu w czasie trwania powiązania, gdy rozwiązanie przeciążenia nie może znaleźć żadnych odpowiednich metod.However, it often leads to a binding-time error when overload resolution then fails to find any applicable methods.

Jeśli podana liczba argumentów jest inna niż liczba parametrów w metodzie, wnioskowanie natychmiast zakończy się niepowodzeniem.If the supplied number of arguments is different than the number of parameters in the method, then inference immediately fails. W przeciwnym razie Załóżmy, że metoda ogólna ma następujący podpis:Otherwise, assume that the generic method has the following signature:

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

Z wywołaniem metody formularza M(E1...Em) zadania wnioskowania o typie jest znalezienie unikatowych argumentów typu S1...Sn dla każdego z parametrów typu X1...Xn, tak że wywołanie M<S1...Sn>(E1...Em) będzie prawidłowe.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.

Podczas procesu wnioskowania każdy parametr typu Xi jest ustalony do określonego typu Si lub nieustalony ze skojarzonym zestawem granic.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. Każda granica jest częścią typu T.Each of the bounds is some type T. Początkowo Każda zmienna typu Xi jest nierozwiązana z pustym zestawem granic.Initially each type variable Xi is unfixed with an empty set of bounds.

Wnioskowanie o typie odbywa się w fazach.Type inference takes place in phases. Każda faza podejmie próbę ustalenia argumentów typu dla większej liczby zmiennych typu w oparciu o wyniki poprzedniej fazy.Each phase will try to infer type arguments for more type variables based on the findings of the previous phase. Pierwsza faza polega na wstępnym wnioskach o granicach, podczas gdy druga faza naprawia zmienne typu dla określonych typów i wnioskuje o dalsze granice.The first phase makes some initial inferences of bounds, whereas the second phase fixes type variables to specific types and infers further bounds. Druga faza może być konieczna wielokrotnie.The second phase may have to be repeated a number of times.

Uwaga: Wnioskowanie o typie ma miejsce nie tylko wtedy, gdy wywoływana jest metoda ogólna.Note: Type inference takes place not only when a generic method is called. Wnioskowanie o typie dla konwersji grup metod jest opisane w wnioskach o typie do konwersji grup metod i znalezienie najlepszego wspólnego typu zestawu wyrażeń jest opisany w artykule Znajdowanie najlepszego wspólnego typu zestawu wyrażeń.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.

Pierwsza fazaThe first phase

Dla każdego z argumentów metody Ei:For each of the method arguments Ei:

  • Jeśli Ei jest funkcją anonimową, jawne wnioskowanie o typie parametru (jawne wnioskowanie o typie parametrów) zostało wykonane z Ei do TiIf Ei is an anonymous function, an explicit parameter type inference (Explicit parameter type inferences) is made from Ei to Ti
  • W przeciwnym razie, jeśli Ei ma typ U, a xi jest parametrem wartości, następuje przewnioskowanie o niższej granicy od U do 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.
  • W przeciwnym razie, jeśli Ei ma typ U i xi jest parametrem ref lub out, nastąpiło dokładne wnioskowanie z U do 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.
  • W przeciwnym razie dla tego argumentu nie są wykonywane żadne wnioskowanie.Otherwise, no inference is made for this argument.

Druga fazaThe second phase

Druga faza przebiega w następujący sposób:The second phase proceeds as follows:

  • Wszystkie nienaprawione zmienne typu Xi które nie są zależne od (zależność) dowolnych Xj są stałe (naprawianie).All unfixed type variables Xi which do not depend on (Dependence) any Xj are fixed (Fixing).
  • Jeśli nie istnieją takie zmienne typu, wszystkie nienaprawione zmienne typu Xirozwiązane , dla których wszystkie następujące wstrzymano:If no such type variables exist, all unfixed type variables Xi are fixed for which all of the following hold:
    • Istnieje co najmniej jedna zmienna typu Xj, która zależy od XiThere is at least one type variable Xj that depends on Xi
    • Xi nie ma pustego zestawu granicXi has a non-empty set of bounds
  • Jeśli nie istnieją takie zmienne typu, a nadal istnieją nienaprawione zmienne typu, wnioskowanie o typie kończy się niepowodzeniem.If no such type variables exist and there are still unfixed type variables, type inference fails.
  • W przeciwnym razie, jeśli nie istnieją żadne dalsze zmienne typu nienaprawionego , wnioskowanie o typie powiedzie się.Otherwise, if no further unfixed type variables exist, type inference succeeds.
  • W przeciwnym razie dla wszystkich argumentów Ei z odpowiadającym typem parametru Ti, gdzie typy danych wyjściowych (typy wyjściowe) zawierają nienaprawione zmienne typu, Xj ale typy wejściowe (typy wejściowe) nie, wnioskowanie o typie danych wyjściowych (wnioskowania typu wyjściowego) są tworzone z Ei do 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. Następnie druga faza jest powtarzana.Then the second phase is repeated.

Typy wejścioweInput types

Jeśli E jest grupą metod lub niejawnie wpisaną funkcją anonimową, a T jest typem delegata lub typem drzewa wyrażenia, wszystkie typy parametrów Ttypami wejściowymi E z typem 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.

Typy wyjścioweOutput types

Jeśli E jest grupą metod lub funkcją anonimową, a T jest typem delegata lub typem drzewa wyrażenia, zwracany typ T jest typem danych wyjściowych E z typem 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.

OdDependence

Niestała zmienna typu Xi zależy bezpośrednio od nieustalonej zmiennej typu Xj jeśli dla pewnego argumentu Ek z typem Tk Xj występuje w typie danych wejściowych Ek z typem Tk i Xi występuje w typie danych wyjściowych Ek z typem 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 zależy od Xi, jeśli Xj zależy bezpośrednio od Xi lub, jeśli Xi, zależy bezpośrednio od Xk, a Xk zależy od Xj.Xj depends on Xi if Xj depends directly on Xi or if Xi depends directly on Xk and Xk depends on Xj. W tym przypadku "zależy od" jest przechodnie, ale nie jest zamykany zwrotnie "jest zależny od bezpośredniej".Thus "depends on" is the transitive but not reflexive closure of "depends directly on".

Wnioskowanie o typie danych wyjściowychOutput type inferences

Wnioskowanie o typie danych wyjściowych jest wykonywane z wyrażenia E do typu T w następujący sposób:An output type inference is made from an expression E to a type T in the following way:

  • Jeśli E jest funkcją anonimową z odroczonym typem zwracanym U (wywnioskowany typ zwracany), a T jest typem delegata lub typem drzewa wyrażenia z Tb typu zwracanego, a następnie z U do 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.
  • W przeciwnym razie, jeśli E jest grupą metod, a T jest typem delegata lub typem drzewa wyrażenia z typami parametrów T1...Tk i zwracany typ Tb, a Rozpoznanie przeciążenia E z typami T1...Tk powoduje utworzenie pojedynczej metody z typem zwracanym U, a następnie przekazanie od U do 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.
  • W przeciwnym razie, jeśli E jest wyrażeniem typu U, następuje Dolna granica wnioskowania z U do T.Otherwise, if E is an expression with type U, then a lower-bound inference is made from U to T.
  • W przeciwnym razie nie są wykonywane żadne wnioskowania.Otherwise, no inferences are made.

Wnioskowanie typu jawnego parametruExplicit parameter type inferences

Jawne wnioskowanie o typie parametru zostało wykonane z wyrażenia E do typu T w następujący sposób:An explicit parameter type inference is made from an expression E to a type T in the following way:

  • Jeśli E jest jawnie wpisaną funkcją anonimową z typami parametrów U1...Uk, a T jest typem delegata lub typem drzewa wyrażenia z typami parametrów V1...Vk następnie dla każdego Ui dokładnego wnioskowania (dokładne wnioskowania) nastąpi od Ui do odpowiadającego 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.

Dokładne wnioskowanieExact inferences

Dokładne wnioskowanie z typu U do typu V jest wykonywane w następujący sposób:An exact inference from a type U to a type V is made as follows:

  • Jeśli V jest jedną z nieustalonych Xi, U jest dodawana do zestawu dokładnych granic dla Xi.If V is one of the unfixed Xi then U is added to the set of exact bounds for Xi.

  • W przeciwnym razie zestawy V1...Vk i U1...Uk są określane przez sprawdzenie, czy którykolwiek z następujących przypadków ma zastosowanie:Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • V jest typem tablicy V1[...], a U jest typem tablicy U1[...] tej samej rangiV is an array type V1[...] and U is an array type U1[...] of the same rank
    • V jest typem V1?, a U jest typem U1?V is the type V1? and U is the type U1?
    • V jest konstruowanym typem C<V1...Vk>i U jest typem skonstruowanym C<U1...Uk>V is a constructed type C<V1...Vk>and U is a constructed type C<U1...Uk>

    Jeśli którykolwiek z tych przypadków ma zastosowanie, to dokładne wnioskowanie jest wykonywane z poszczególnych Ui do odpowiednich Vi.If any of these cases apply then an exact inference is made from each Ui to the corresponding Vi.

  • W przeciwnym razie nie wprowadzono żadnych wniosków.Otherwise no inferences are made.

Wnioskowanie o niższych ograniczeniachLower-bound inferences

Mniej ograniczone wnioskowanie z typu U do typu V jest wykonywane w następujący sposób:A lower-bound inference from a type U to a type V is made as follows:

  • Jeśli V jest jedną z nieustalonych Xi, U zostanie dodana do zestawu dolnych granic dla Xi.If V is one of the unfixed Xi then U is added to the set of lower bounds for Xi.

  • W przeciwnym razie, jeśli V jest typem V1?, a U jest typem U1? następnie przeprowadzono dolną granicę od U1 do 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.

  • W przeciwnym razie zestawy U1...Uk i V1...Vk są określane przez sprawdzenie, czy którykolwiek z następujących przypadków ma zastosowanie:Otherwise, sets U1...Uk and V1...Vk are determined by checking if any of the following cases apply:

    • V jest typem tablicy V1[...], a U jest typem tablicy U1[...] (lub parametrem typu, którego efektywny typ podstawowy to U1[...]) o tej samej rangiV 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 jest jedną z IEnumerable<V1>, ICollection<V1> lub IList<V1> i U jest typem tablicy jednowymiarowej U1[](lub parametrem typu, którego obowiązuje typ podstawowy)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 jest klasą konstruowaną, strukturą, interfejsem lub typem delegata C<V1...Vk> i istnieje unikatowy typ C<U1...Uk> taki, że U (lub, jeśli U jest parametrem typu, jego skuteczna Klasa bazowa lub którykolwiek element członkowski jego efektywnego zestawu interfejsów) jest taka sama jak, dziedziczy po (bezpośrednio lub pośrednio), lub implementuje (bezpośrednio lub pośrednio) 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>.

      (Ograniczenie "unikatowość" oznacza, że w interfejsie Case C<T> {} class U: C<X>, C<Y> {}nie są wykonywane żadne wnioskowanie podczas wnioskowania od U do C<T>, ponieważ U1 może być X lub 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.)

    Jeśli którykolwiek z tych przypadków stosuje, wnioskowanie jest wykonywane z każdego Ui do odpowiadającego Vi w następujący sposób:If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Jeśli Ui nie jest znany jako typ referencyjny, zostanie wykonane dokładne wnioskowanieIf Ui is not known to be a reference type then an exact inference is made
    • W przeciwnym razie, jeśli U jest typem tablicy, tworzone jest mniej ograniczone wnioskowanieOtherwise, if U is an array type then a lower-bound inference is made
    • W przeciwnym razie, jeśli V jest C<V1...Vk>, wnioskowanie zależy od typu i-ty parametru C:Otherwise, if V is C<V1...Vk> then inference depends on the i-th type parameter of C:
      • Jeśli jest to współwariant, zostanie wprowadzony niższy zakres wnioskowania .If it is covariant then a lower-bound inference is made.
      • Jeśli jest kontrawariantne, zostanie wykonane górne ograniczenie wnioskowania .If it is contravariant then an upper-bound inference is made.
      • Jeśli jest niezmienna, następuje dokładne wnioskowanie .If it is invariant then an exact inference is made.
  • W przeciwnym razie nie są wykonywane żadne wnioskowania.Otherwise, no inferences are made.

Wnioskowanie o górnych granicachUpper-bound inferences

Górną granicę wnioskowania z typu U do typu V są wykonywane w następujący sposób:An upper-bound inference from a type U to a type V is made as follows:

  • Jeśli V jest jedną z nieustalonych Xi, U zostanie dodana do zestawu górnych granic dla Xi.If V is one of the unfixed Xi then U is added to the set of upper bounds for Xi.

  • W przeciwnym razie zestawy V1...Vk i U1...Uk są określane przez sprawdzenie, czy którykolwiek z następujących przypadków ma zastosowanie:Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • U jest typem tablicy U1[...], a V jest typem tablicy V1[...] tej samej rangiU is an array type U1[...] and V is an array type V1[...] of the same rank

    • U jest jedną z IEnumerable<Ue>, ICollection<Ue> lub IList<Ue> i V jest jednowymiarowym typem tablicy Ve[]U is one of IEnumerable<Ue>, ICollection<Ue> or IList<Ue> and V is a one-dimensional array type Ve[]

    • U jest typem U1?, a V jest typem V1?U is the type U1? and V is the type V1?

    • U jest konstruowany typ klasy, struktury, interfejsu lub delegata C<U1...Uk> a V jest klasą, strukturą, interfejsem lub typem delegata, który jest identyczny z, dziedziczy po (bezpośrednio lub pośrednio) lub implementuje (bezpośrednio lub pośrednio) unikatowy typ 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>

      (Ograniczenie "unikatowość" oznacza, że jeśli mamy interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}, podczas wnioskowania od C<U1> do V<Q>nie są wykonywane żadne wnioskowanie.(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>. Wnioskowanie nie jest wykonywane z U1 do X<Q> lub Y<Q>.)Inferences are not made from U1 to either X<Q> or Y<Q>.)

    Jeśli którykolwiek z tych przypadków stosuje, wnioskowanie jest wykonywane z każdego Ui do odpowiadającego Vi w następujący sposób:If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Jeśli Ui nie jest znany jako typ referencyjny, zostanie wykonane dokładne wnioskowanieIf Ui is not known to be a reference type then an exact inference is made
    • W przeciwnym razie, jeśli V jest typem tablicy, zostanie wykonane górne ograniczenie wnioskowaniaOtherwise, if V is an array type then an upper-bound inference is made
    • W przeciwnym razie, jeśli U jest C<U1...Uk>, wnioskowanie zależy od typu i-ty parametru C:Otherwise, if U is C<U1...Uk> then inference depends on the i-th type parameter of C:
      • Jeśli jest to współwariant, nadano górną granicę .If it is covariant then an upper-bound inference is made.
      • Jeśli jest kontrawariantne, zostanie wykonane obniżenie wnioskowania o niższym poziomie .If it is contravariant then a lower-bound inference is made.
      • Jeśli jest niezmienna, następuje dokładne wnioskowanie .If it is invariant then an exact inference is made.
  • W przeciwnym razie nie są wykonywane żadne wnioskowania.Otherwise, no inferences are made.

MocowanieFixing

Nieustalona zmienna typu Xi z zestawem granic jest ustalona w następujący sposób:An unfixed type variable Xi with a set of bounds is fixed as follows:

  • Zestaw typów kandydatów Uj uruchamiany jako zestaw wszystkich typów w zestawie granic dla Xi.The set of candidate types Uj starts out as the set of all types in the set of bounds for Xi.
  • Następnie analizujemy poszczególne powiązania Xi z kolei: dla każdego dokładnego U Xi wszystkich typów Uj, które nie są identyczne z U są usuwane z zestawu kandydatów.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. Dla każdej dolnej granicy U Xi wszystkie typy Uj, do których nie istnieje niejawna konwersja z U są usuwane z zestawu kandydatów.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. Dla każdej górnej granicy U Xi wszystkie typy Uj z których nie istnieje niejawna konwersja do U są usuwane z zestawu kandydatów.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.
  • Jeśli wśród pozostałych typów kandydatów Uj istnieje unikatowy typ V, z którego istnieje niejawna konwersja na wszystkie inne typy kandydatów, Xi jest naprawiona 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.
  • W przeciwnym razie wnioskowanie o typie nie powiedzie się.Otherwise, type inference fails.

Wywnioskowany typ zwracanyInferred return type

Wywnioskowany typ zwracany funkcji anonimowej F jest używany podczas wnioskowania o typie i rozpoznawania przeciążenia.The inferred return type of an anonymous function F is used during type inference and overload resolution. Wywnioskowany typ zwracany można określić tylko dla funkcji anonimowej, w której znane są wszystkie typy parametrów, ponieważ są one jawnie podane przez funkcję anonimowej konwersji lub wywnioskowane podczas wnioskowania o typie w otaczającym ogólnym wywołanie metody.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.

Wywnioskowany typ wyniku jest określany w następujący sposób:The inferred result type is determined as follows:

  • Jeśli treść F jest wyrażeniem , które ma typ, wywnioskowany typ wyniku F jest typem tego wyrażenia.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.
  • Jeśli treść F jest blok , a zestaw wyrażeń w instrukcjach return bloku ma najlepszy wspólny typ T (znalezienie najlepszego wspólnego typu zestawu wyrażeń), a następnie typ wyniku wywnioskowanego F jest 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.
  • W przeciwnym razie nie można wywnioskować typu wyniku dla F.Otherwise, a result type cannot be inferred for F.

Wywnioskowany typ zwracany jest określany w następujący sposób:The inferred return type is determined as follows:

  • Jeśli F jest Async i treścią F jest wyrażenie sklasyfikowane jako Nothing (klasyfikacje wyrażeń) lub blok instrukcji, gdzie żadne instrukcje return nie mają wyrażeń, odroczony typ zwracany jest 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
  • Jeśli F jest Async i ma wywnioskowany typ wyniku T, zostanie System.Threading.Tasks.Task<T>wnioskowany typ zwracany.If F is async and has an inferred result type T, the inferred return type is System.Threading.Tasks.Task<T>.
  • Jeśli F nie jest Async i ma wywnioskowany typ wyniku T, zostanie Twnioskowany typ zwracany.If F is non-async and has an inferred result type T, the inferred return type is T.
  • W przeciwnym razie nie można wywnioskować zwracanego typu dla F.Otherwise a return type cannot be inferred for F.

Przykładowo wnioskowanie o typie obejmujące funkcje anonimowe, należy wziąć pod uwagę metodę rozszerzenia Select zadeklarowaną w klasie 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);
        }
    }
}

Przy założeniu, że przestrzeń nazw System.Linq została zaimportowana z klauzulą using i dana klasa Customer z właściwością Name typu string, można użyć metody Select, aby wybrać nazwy listy klientów: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);

Wywołanie metody rozszerzenia (wywołania metody rozszerzenia) Select jest przetwarzane przez ponowne zapisanie wywołania do wywołania metody statycznej: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);

Ponieważ argumenty typu nie zostały jawnie określone, wnioskowanie typu jest używane do wywnioskowania argumentów typu.Since type arguments were not explicitly specified, type inference is used to infer the type arguments. Najpierw argument customers jest powiązany z parametrem source, które wywołują T do Customer.First, the customers argument is related to the source parameter, inferring T to be Customer. Następnie przy użyciu opisanego powyżej procesu wnioskowania o typie funkcji anonimowej c jest dany typ Customer, a wyrażenie c.Name jest powiązane z typem zwracanym parametru selector, wnioskowanie 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. W rezultacie wywołanie jest równoważneThus, the invocation is equivalent to

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

a wynik jest typu IEnumerable<string>.and the result is of type IEnumerable<string>.

Poniższy przykład ilustruje sposób, w jaki anonimowe funkcje wnioskowania umożliwiają informacje o typie "Flow" między argumentami w wywołaniu metody ogólnej.The following example demonstrates how anonymous function type inference allows type information to "flow" between arguments in a generic method invocation. Dana metoda:Given the method:

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

Wnioskowanie o typie dla wywołania:Type inference for the invocation:

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

działa w następujący sposób: najpierw argument "1:15:30" jest powiązany z parametrem value, które wywołują X do string.proceeds as follows: First, the argument "1:15:30" is related to the value parameter, inferring X to be string. Następnie parametr pierwszej funkcji anonimowej, s, ma przyznany typ wnioskowany string, a wyrażenie TimeSpan.Parse(s) jest powiązane z typem zwracanym f1, wnioskowanie Y do 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. Na koniec parametr drugiej funkcji anonimowej, t, ma przyznany typ wnioskowany System.TimeSpan, a wyrażenie t.TotalSeconds jest powiązane z typem zwracanym f2, wnioskowanie Z do 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. W związku z tym wynik wywołania jest typu double.Thus, the result of the invocation is of type double.

Wnioskowanie o typie dla konwersji grup metodType inference for conversion of method groups

Podobnie jak w przypadku wywołań metod ogólnych, wnioskowanie o typie należy również zastosować, gdy grupa metod M zawierająca metodę generyczną jest konwertowana na dany typ delegata D (konwersje grup metod).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). Dana metodaGiven a method

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

a grupa metod M przypisywana do typu delegata D zadanie wnioskowania o typie ma na celu znalezienie argumentów typu S1...Sn tak, aby wyrażenie: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>

staną się zgodne (deklaracje delegatów) z D.becomes compatible (Delegate declarations) with D.

W przeciwieństwie do algorytmu wnioskowania o typie dla wywołań metod ogólnych, w tym przypadku są tylko typyargumentów, bez wyrażeńargumentów.Unlike the type inference algorithm for generic method calls, in this case there are only argument types, no argument expressions. W szczególności nie ma żadnych funkcji anonimowych i w związku z tym nie ma potrzeby stosowania wielu faz wnioskowania.In particular, there are no anonymous functions and hence no need for multiple phases of inference.

Zamiast tego wszystkie Xi są uznawane za nienaprawione, a z każdego typu argumentu Uj D do odpowiedniego typu parametru 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. Jeśli dla dowolnego Xi nie znaleziono żadnych granic, wnioskowanie o typie kończy się niepowodzeniem.If for any of the Xi no bounds were found, type inference fails. W przeciwnym razie wszystkie Xinaprawione odpowiednimi Si, które są wynikiem wnioskowania o typie.Otherwise, all Xi are fixed to corresponding Si, which are the result of type inference.

Znajdowanie najlepszego wspólnego typu zestawu wyrażeńFinding the best common type of a set of expressions

W niektórych przypadkach wspólny typ musi zostać wywnioskowany dla zestawu wyrażeń.In some cases, a common type needs to be inferred for a set of expressions. W szczególności typy elementów niejawnie wpisanych tablic i zwracane typy funkcji anonimowych z treści bloku są dostępne w ten sposób.In particular, the element types of implicitly typed arrays and the return types of anonymous functions with block bodies are found in this way.

Intuicyjnie, z uwzględnieniem zestawu wyrażeń E1...Em ten wnioskowanie powinno być równoważne wywołaniu metodyIntuitively, given a set of expressions E1...Em this inference should be equivalent to calling a method

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

z Ei jako argumenty.with the Ei as arguments.

Dokładniej, wnioskowanie rozpoczyna się od nieustalonej zmiennej typu X.More precisely, the inference starts out with an unfixed type variable X. Następnie wnioskowania typu danych wyjściowych są następnie wykonywane z poszczególnych Ei do X.Output type inferences are then made from each Ei to X. Na koniec X jest naprawiony i, jeśli to się powiedzie, typ otrzymany S jest najlepszym typowym typem dla wyrażeń.Finally, X is fixed and, if successful, the resulting type S is the resulting best common type for the expressions. Jeśli taka S nie istnieje, wyrażenia nie mają najlepszego wspólnego typu.If no such S exists, the expressions have no best common type.

Rozpoznanie przeciążeniaOverload resolution

Rozwiązanie przeciążania to mechanizm umożliwiający wybranie najlepszego elementu członkowskiego funkcji w celu wywołania listy argumentów i zestawu elementów członkowskich funkcji kandydujących.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. Rozwiązanie przeciążania wybiera element członkowski funkcji do wywołania w następujących odrębnych C#kontekstach w obrębie:Overload resolution selects the function member to invoke in the following distinct contexts within C#:

Każdy z tych kontekstów definiuje zestaw elementów członkowskich funkcji kandydujących i listę argumentów we własnym unikatowy sposób, jak opisano szczegółowo w sekcjach wymienionych powyżej.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. Na przykład zestaw kandydatów dla wywołania metody nie obejmuje metod oznaczonych override (odnośnik elementów członkowskich), a metody w klasie bazowej nie są kandydatami, jeśli stosowana jest jakakolwiek metoda w klasie pochodnej (wywołania metod).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).

Po zidentyfikowaniu elementów członkowskich funkcji kandydujących i listy argumentów wybór najlepszego elementu członkowskiego funkcji jest taki sam we wszystkich przypadkach: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:

  • Z uwzględnieniem zestawu odpowiednich członków funkcji kandydujących należy zlokalizować element członkowski najlepszych funkcji w tym zestawie.Given the set of applicable candidate function members, the best function member in that set is located. Jeśli zestaw zawiera tylko jeden element członkowski funkcji, to element członkowski funkcji jest najlepszą funkcją.If the set contains only one function member, then that function member is the best function member. W przeciwnym razie najlepszą składową funkcji jest element członkowski funkcji, który jest lepszy niż wszystkie inne elementy członkowskie funkcji w odniesieniu do danej listy argumentów, pod warunkiem, że każdy element członkowski funkcji jest porównywany z innymi składowymi funkcji przy użyciu reguł w lepszym elemencie członkowskim funkcji.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. Jeśli nie ma dokładnie jednego elementu członkowskiego funkcji, który jest lepszy niż wszystkie inne składowe funkcji, wywołanie elementu członkowskiego funkcji jest niejednoznaczne i występuje błąd w czasie powiązania.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.

W poniższych sekcjach opisano dokładne znaczenie elementów członkowskich funkcji i lepszy element członkowski funkcji.The following sections define the exact meanings of the terms applicable function member and better function member.

Odpowiedni element członkowski funkcjiApplicable function member

Członek funkcji jest wskazany jako element członkowski funkcji w odniesieniu do listy argumentów A, gdy spełnione są wszystkie z następujących warunków: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:

  • Każdy argument w A odpowiada parametrowi w deklaracji elementu członkowskiego funkcji, zgodnie z opisem w odpowiednich parametrach, oraz dowolnego parametru, do którego nie odpowiada żaden argument, jest parametrem opcjonalnym.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.
  • Dla każdego argumentu w Atryb przekazywania parametrów argumentu (tj. Value, reflub out) jest identyczny z trybem przekazywania parametrów dla odpowiedniego parametru, iFor 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
    • dla parametru value lub tablicy parametrów niejawna konwersja (niejawne konwersje) istnieje z argumentu do typu odpowiadającego parametru lubfor a value parameter or a parameter array, an implicit conversion (Implicit conversions) exists from the argument to the type of the corresponding parameter, or
    • dla parametru ref lub out typ argumentu jest identyczny z typem odpowiadającego parametru.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter. Po wszystkich parametr ref lub out jest aliasem dla argumentu, który został przeszukany.After all, a ref or out parameter is an alias for the argument passed.

W przypadku składowej funkcji, która zawiera tablicę parametrów, jeśli element członkowski funkcji jest stosowany przez powyższe reguły, jest on uznawany za stosowany w jego normalnej postaci.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. Jeśli element członkowski funkcji zawierający tablicę parametrów nie ma zastosowania w jego normalnej postaci, element członkowski funkcji może być stosowany w jego rozwiniętej postaci: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:

  • Rozwinięty formularz jest konstruowany przez zastąpienie tablicy parametrów w deklaracji elementu członkowskiego funkcji wartością zero lub więcej parametrów wartości typu elementu tablicy parametrów w taki sposób, że liczba argumentów na liście argumentów A zgodna z łączną liczbą parametrów.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. Jeśli A ma mniejszą liczbę argumentów niż liczba stałych parametrów w deklaracji elementu członkowskiego funkcji, rozwinięta forma składowej funkcji nie może być skonstruowana i nie ma zastosowania.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.
  • W przeciwnym razie rozszerzona forma jest stosowana, jeśli dla każdego argumentu w A tryb przekazywania parametru argumentu jest taka sama jak tryb przekazywania parametrów odpowiadającego parametru, iOtherwise, 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
    • dla parametru wartości ustalonej lub parametru wartości utworzonego przez ekspansję niejawna konwersja (niejawne konwersje) istnieje z typu argumentu do typu odpowiadającego parametru lubfor 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
    • dla parametru ref lub out typ argumentu jest identyczny z typem odpowiadającego parametru.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter.

Lepsza składowa funkcjiBetter function member

Na potrzeby określenia lepszego elementu członkowskiego funkcja, Oddzielna lista argumentów A jest zbudowana zawierające tylko wyrażenia argumentów w kolejności, w jakiej występują na liście pierwotnych argumentów.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.

Listy parametrów dla każdego elementu członkowskiego funkcji kandydującej są konstruowane w następujący sposób:Parameter lists for each of the candidate function members are constructed in the following way:

  • Rozwinięty formularz jest używany, jeśli element członkowski funkcji ma zastosowanie tylko w rozwiniętym formularzu.The expanded form is used if the function member was applicable only in the expanded form.
  • Parametry opcjonalne bez odpowiednich argumentów są usuwane z listy parametrówOptional parameters with no corresponding arguments are removed from the parameter list
  • Parametry są zmieniane w kolejności, tak że pojawiają się w tym samym miejscu co odpowiadający argument na liście argumentów.The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.

Podano listę argumentów A z zestawem wyrażeń argumentów {E1, E2, ..., En} i dwóch odpowiednich członków funkcji Mp i Mq z typami parametrów {P1, P2, ..., Pn} i {Q1, Q2, ..., Qn}, Mp jest zdefiniowana jako lepsza składowa funkcji niż Mq JeśliGiven 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

  • dla każdego argumentu niejawna konwersja z Ex na Qx nie jest lepsza niż niejawna konwersja z Ex na Pxifor each argument, the implicit conversion from Ex to Qx is not better than the implicit conversion from Ex to Px, and
  • dla co najmniej jednego argumentu konwersja z Ex na Px jest lepsza niż konwersja z Ex do Qx.for at least one argument, the conversion from Ex to Px is better than the conversion from Ex to Qx.

Podczas przeprowadzania tej oceny, jeśli Mp lub Mq ma zastosowanie w rozwiniętej postaci, a następnie Px lub Qx odwołuje się do parametru w rozwiniętej postaci listy parametrów.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.

W przypadku, gdy sekwencje typu parametrów {P1, P2, ..., Pn} i {Q1, Q2, ..., Qn} są równoważne (tj. Każda Pi ma konwersję tożsamości na odpowiadającą Qi), w kolejności są stosowane następujące reguły podziału powiązania, aby określić lepszy element członkowski funkcji.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.

  • Jeśli Mp jest metodą nierodzajową, a Mq jest metodą rodzajową, Mp jest lepsza niż Mq.If Mp is a non-generic method and Mq is a generic method, then Mp is better than Mq.
  • W przeciwnym razie, jeśli Mp ma zastosowanie w swojej normalnej formie i Mq ma tablicę params i ma zastosowanie tylko w rozwiniętej postaci, Mp jest lepsza niż 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.
  • W przeciwnym razie, jeśli Mp ma więcej zadeklarowanych parametrów niż Mq, Mp jest lepsza niż Mq.Otherwise, if Mp has more declared parameters than Mq, then Mp is better than Mq. Taka sytuacja może wystąpić, jeśli obie metody mają params tablice i są stosowane tylko w rozwiniętych formularzach.This can occur if both methods have params arrays and are applicable only in their expanded forms.
  • W przeciwnym razie, jeśli wszystkie parametry Mp mają odpowiadający argument, a argumenty domyślne muszą zostać zastąpione dla co najmniej jednego parametru opcjonalnego w Mq, Mp jest lepszy niż 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.
  • W przeciwnym razie, jeśli Mp ma więcej konkretnych typów parametrów niż Mq, Mp jest lepiej niż Mq.Otherwise, if Mp has more specific parameter types than Mq, then Mp is better than Mq. Niech {R1, R2, ..., Rn} i {S1, S2, ..., Sn} reprezentują typy parametrów, które nie są tworzone i są nierozwinięte Mp i Mq.Let {R1, R2, ..., Rn} and {S1, S2, ..., Sn} represent the uninstantiated and unexpanded parameter types of Mp and Mq. typy parametrów Mpsą bardziej szczegółowe niż Mq, jeśli dla każdego parametru Rx nie są mniej specyficzne niż Sx, a dla co najmniej jednego parametru Rx jest bardziej szczegółowy niż 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:
    • Parametr typu jest mniej specyficzny niż parametr niebędący typem.A type parameter is less specific than a non-type parameter.
    • Rekursywnie skonstruowany typ jest bardziej szczegółowy niż inny skonstruowany typ (z tą samą liczbą argumentów typu), jeśli co najmniej jeden argument typu jest bardziej szczegółowy i żaden argument typu nie jest mniej specyficzny niż odpowiedni argument typu w drugim.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.
    • Typ tablicy jest bardziej szczegółowy niż inny typ tablicy (o tej samej liczbie wymiarów), jeśli typ elementu pierwszego jest bardziej szczegółowy niż typ elementu drugiego.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.
  • W przeciwnym razie, jeśli jeden element członkowski jest niezniesionym operatorem, a drugi jest operatorem podnoszenia, to niezniesione.Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better.
  • W przeciwnym razie żaden element członkowski funkcji nie jest lepszy.Otherwise, neither function member is better.

Lepsza konwersja z wyrażeniaBetter conversion from expression

Nadano niejawną konwersję C1, która konwertuje z wyrażenia E na typ T1oraz niejawną konwersję C2, która konwertuje z wyrażenia E do typu T2, C1 to lepsza konwersja niż C2, jeśli E nie dokładnie pasuje T2 i co najmniej jednego z następujących elementów: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:

Wyrażenie dokładnie pasująceExactly matching Expression

Uwzględniając E wyrażenia i Ttypu, E dokładnie pasuje do T, jeśli jedno z następujących posiada:Given an expression E and a type T, E exactly matches T if one of the following holds:

  • E ma Stypu, a konwersja tożsamości istnieje z S do TE has a type S, and an identity conversion exists from S to T
  • E to funkcja anonimowa, T jest typem delegata D lub typem drzewa wyrażenia Expression<D> i jedną z następujących wartości: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:
    • Wywnioskowany typ zwracany X istnieje dla E w kontekście listy parametrów D (wnioskowany typ zwracany) i konwersja tożsamości istnieje z X do zwracanego typu 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 jest nieasync i D ma zwracany typ Y lub E jest typem asynchronicznym, a D ma zwracany typ Task<Y>i jedną z następujących wartości: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:
      • Treść E jest wyrażeniem, które dokładnie pasuje do YThe body of E is an expression that exactly matches Y
      • Treść E jest blokiem instrukcji, gdzie każda instrukcja return zwraca wyrażenie, które dokładnie pasuje do YThe body of E is a statement block where every return statement returns an expression that exactly matches Y

Lepszy cel konwersjiBetter conversion target

Podano dwa różne typy T1 i T2, T1 jest lepszym celem konwersji niż T2, jeśli nie istnieje niejawna konwersja z T2 na T1, a co najmniej jeden z następujących elementów: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:

  • Niejawna konwersja z T1 na T2 istniejeAn implicit conversion from T1 to T2 exists
  • T1 jest typem delegata D1 lub typem drzewa wyrażenia, Expression<D1>``T2 jest typem delegata D2 lub typem drzewa wyrażenia Expression<D2>, D1 ma zwracany typ S1 i jedną z następujących wartości: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 jest zwracana wartość voidD2 is void returning
    • D2 ma S2typu zwracanego, a S1 jest lepszą konwersją docelową niż S2D2 has a return type S2, and S1 is a better conversion target than S2
  • T1 jest Task<S1>, T2 jest Task<S2>, a S1 jest lepszym celem konwersji niż S2T1 is Task<S1>, T2 is Task<S2>, and S1 is a better conversion target than S2
  • T1 jest S1 lub S1? gdzie S1 jest podpisanym typem całkowitym, a T2 jest S2 lub S2?, gdzie S2 jest typem całkowitym bez znaku.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. OpracowanySpecifically:
    • S1 jest sbyte i S2 jest byte, ushort, uintlub ulongS1 is sbyte and S2 is byte, ushort, uint, or ulong
    • S1 jest short i S2 jest ushort, uintlub ulongS1 is short and S2 is ushort, uint, or ulong
    • S1 jest int i S2 uintlub ulongS1 is int and S2 is uint, or ulong
    • S1 jest long i S2 jest ulongS1 is long and S2 is ulong

Przeciążanie klas ogólnychOverloading in generic classes

Chociaż sygnatury jako zadeklarowane muszą być unikatowe, możliwe jest zastępowanie argumentów typu w identycznych sygnaturach.While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. W takich przypadkach reguły łamania i przeciążania przeciążenia powyżej spowodują wybranie najbardziej szczegółowego elementu członkowskiego.In such cases, the tie-breaking rules of overload resolution above will pick the most specific member.

W poniższych przykładach przedstawiono nieprawidłowe i nieprawidłowe przeciążenia zgodne z tą regułą: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);
}

Sprawdzanie czasu kompilacji dynamicznego rozpoznawania przeciążeniaCompile-time checking of dynamic overload resolution

W przypadku większości operacji powiązanych dynamicznie zestaw możliwych kandydatów do rozwiązania jest nieznany w czasie kompilacji.For most dynamically bound operations the set of possible candidates for resolution is unknown at compile-time. W niektórych przypadkach, jednak zestaw kandydatów jest znany w czasie kompilacji:In certain cases, however the candidate set is known at compile-time:

  • Wywołania metody statycznej z argumentami dynamicznymiStatic method calls with dynamic arguments
  • Wywołania metody wystąpienia, w których odbiorca nie jest wyrażeniem dynamicznymInstance method calls where the receiver is not a dynamic expression
  • Wywołania indeksatora, w których odbiorca nie jest wyrażeniem dynamicznymIndexer calls where the receiver is not a dynamic expression
  • Wywołania konstruktora z argumentami dynamicznymiConstructor calls with dynamic arguments

W takich przypadkach jest przeprowadzane ograniczone sprawdzanie czasu kompilacji dla każdego kandydata, aby zobaczyć, czy którykolwiek z nich może być stosowany w czasie wykonywania. Ta kontrola obejmuje następujące kroki: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:

  • Wnioskowanie o typie częściowym: dowolny argument typu, który nie zależy bezpośrednio lub pośrednio od argumentu typu dynamic jest wnioskowany przy użyciu reguł typu wnioskowanie.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. Pozostałe argumenty typu są nieznane.The remaining type arguments are unknown.
  • Sprawdzenie częściowego zastosowania: zastosowanie jest sprawdzane zgodnie z odpowiednimi elementami członkowskimi funkcji, ale ignorowanie parametrów, których typy są nieznane.Partial applicability check: Applicability is checked according to Applicable function member, but ignoring parameters whose types are unknown.
  • Jeśli żaden kandydat nie przekaże tego testu, wystąpi błąd w czasie kompilacji.If no candidate passes this test, a compile-time error occurs.

Wywołanie elementu członkowskiego funkcjiFunction member invocation

W tej sekcji opisano proces, który odbywa się w czasie wykonywania w celu wywołania określonego elementu członkowskiego funkcji.This section describes the process that takes place at run-time to invoke a particular function member. Przyjęto założenie, że proces powiązania czasu już ustalił określony element członkowski do wywołania, prawdopodobnie przez zastosowanie rozpoznawania przeciążenia do zestawu elementów członkowskich funkcji kandydujących.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.

Do celów opisywania procesu wywołania składowe funkcji są podzielone na dwie kategorie:For purposes of describing the invocation process, function members are divided into two categories:

  • Statyczne składowe funkcji.Static function members. Są to konstruktory wystąpień, metody statyczne, dostęp do właściwości statycznych i Operatory zdefiniowane przez użytkownika.These are instance constructors, static methods, static property accessors, and user-defined operators. Statyczne składowe funkcji są zawsze niewirtualne.Static function members are always non-virtual.
  • Elementy członkowskie funkcji wystąpienia.Instance function members. Są to metody wystąpień, metod dostępu do właściwości wystąpienia i obiektu dostępu indeksatora.These are instance methods, instance property accessors, and indexer accessors. Elementy członkowskie funkcji wystąpienia są niewirtualne lub wirtualne i są zawsze wywoływane w konkretnym wystąpieniu.Instance function members are either non-virtual or virtual, and are always invoked on a particular instance. Wystąpienie jest obliczane przez wyrażenie wystąpienia i jest dostępne w składowej funkcji jako this (ten dostęp).The instance is computed by an instance expression, and it becomes accessible within the function member as this (This access).

Przetwarzanie elementu członkowskiego funkcji w czasie wykonywania składa się z następujących kroków, gdzie M jest elementem członkowskim funkcji i, jeśli M jest składową wystąpienia, E jest wyrażeniem wystąpienia: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:

  • Jeśli M jest składową funkcji statycznej:If M is a static function member:

    • Lista argumentów jest szacowana zgodnie z opisem w liście argumentów.The argument list is evaluated as described in Argument lists.
    • M jest wywoływana.M is invoked.
  • Jeśli M jest składową funkcji wystąpienia zadeklarowaną w value_type:If M is an instance function member declared in a value_type:

    • E jest oceniane.E is evaluated. Jeśli ta Ocena spowoduje wyjątek, kolejne kroki nie są wykonywane.If this evaluation causes an exception, then no further steps are executed.
    • Jeśli E nie jest sklasyfikowana jako zmienna, tworzona jest tymczasowa zmienna lokalna typu E, a wartość E jest przypisana do tej zmiennej.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. następnie E jest ponownie klasyfikowane jako odwołanie do tej tymczasowej zmiennej lokalnej.E is then reclassified as a reference to that temporary local variable. Zmienna tymczasowa jest dostępna jako this w M, ale nie w żaden inny sposób.The temporary variable is accessible as this within M, but not in any other way. W tym przypadku, tylko wtedy, gdy E jest prawdziwa zmienna jest możliwe, że obiekt wywołujący przestrzega zmian, które 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.
    • Lista argumentów jest szacowana zgodnie z opisem w liście argumentów.The argument list is evaluated as described in Argument lists.
    • M jest wywoływana.M is invoked. Zmienna, do której odwołuje się E, to zmienna, do której odwołuje się this.The variable referenced by E becomes the variable referenced by this.
  • Jeśli M jest składową funkcji wystąpienia zadeklarowaną w reference_type:If M is an instance function member declared in a reference_type:

    • E jest oceniane.E is evaluated. Jeśli ta Ocena spowoduje wyjątek, kolejne kroki nie są wykonywane.If this evaluation causes an exception, then no further steps are executed.
    • Lista argumentów jest szacowana zgodnie z opisem w liście argumentów.The argument list is evaluated as described in Argument lists.
    • Jeśli typ E jest value_type, konwersja z opakowaniem (konwersjenapakowywania) do konwersji E na typ object, a E jest uważana za typ object w poniższych krokach.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. W tym przypadku M może być tylko składową System.Object.In this case, M could only be a member of System.Object.
    • Wartość E jest sprawdzana jako prawidłowa.The value of E is checked to be valid. Jeśli wartość E jest null, zostanie zgłoszony System.NullReferenceException i nie zostaną wykonane żadne dalsze kroki.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • Implementacja elementu członkowskiego funkcji do wywołania została określona:The function member implementation to invoke is determined:
      • Jeśli typ powiązania E jest interfejsem, element członkowski funkcji do wywołania jest implementacją M dostarczaną przez typ czasu wykonywania wystąpienia przywoływanego przez 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. Ten element członkowski funkcji jest określany przez zastosowanie reguł mapowania interfejsu (Mapowanie interfejsu) do określenia implementacji M dostarczonej przez typ czasu wykonywania wystąpienia przywoływanego przez 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.
      • W przeciwnym razie, jeśli M jest składową funkcji wirtualnej, element członkowski funkcji do wywołania jest implementacją M dostarczaną przez typ czasu wykonywania wystąpienia przywoływanego przez 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. Ten element członkowski funkcji jest określany przez zastosowanie zasad określania najbardziej pochodnej implementacji (metod wirtualnych) M w odniesieniu do typu czasu wykonywania, do którego odwołuje się 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.
      • W przeciwnym razie M jest składową funkcji niewirtualnej, a element członkowski funkcji do wywołania jest M samym sobą.Otherwise, M is a non-virtual function member, and the function member to invoke is M itself.
    • Implementacja elementu członkowskiego funkcji określona w powyższym kroku jest wywoływana.The function member implementation determined in the step above is invoked. Obiekt, do którego odwołuje się E, jest obiektem, do którego odwołuje się this.The object referenced by E becomes the object referenced by this.

Wywołania w wystąpieniach opakowanychInvocations on boxed instances

Element członkowski funkcji zaimplementowany w value_type może być wywoływany za pomocą wystąpienia zapakowanego value_type , w następujących sytuacjach:A function member implemented in a value_type can be invoked through a boxed instance of that value_type in the following situations:

  • Gdy element członkowski funkcji jest override metody dziedziczonej z typu object i jest wywoływany przez wyrażenie wystąpienia typu 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.
  • Gdy element członkowski funkcji jest implementacją składowej funkcji interfejsu i jest wywoływany za pomocą wyrażenia wystąpienia 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.
  • Gdy element członkowski funkcji jest wywoływany przez delegata.When the function member is invoked through a delegate.

W takich sytuacjach zapakowane wystąpienie jest traktowane jako zmienna value_type, a ta zmienna to zmienna, do której odwołuje się this w wywołaniu elementu członkowskiego funkcji.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. W szczególności oznacza to, że gdy element członkowski funkcji jest wywoływany w przypadku wystąpienia zapakowanego, możliwe jest, aby element członkowski funkcji modyfikował wartość zawartą w zapakowanym wystąpieniu.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.

Wyrażenia podstawowePrimary expressions

Wyrażenia podstawowe zawierają najprostszą postać wyrażeń.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
    ;

Wyrażenia podstawowe są podzielone między array_creation_expressions i primary_no_array_creation_expressions.Primary expressions are divided between array_creation_expressions and primary_no_array_creation_expressions. W ten sposób w ten sposób traktowanie wyrażenia tworzenia tablicowe, a nie wymienienie go wraz z innymi prostymi formularzami wyrażeń, umożliwia gramatykę w celu uniemożliwienia potencjalnie mylącego kodu, takiego jakTreating 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];

który w przeciwnym razie mógłby być interpretowany jakowhich would otherwise be interpreted as

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

LiterałyLiterals

Primary_expression , która składa się z literału (literałów), jest sklasyfikowany jako wartość.A primary_expression that consists of a literal (Literals) is classified as a value.

Ciągi interpolowaneInterpolated strings

Interpolated_string_expression składa się ze znaku $, po którym następuje zwykły lub Verbatim literał ciągu, w którym znajdują się przerwy, rozdzielane przez { i }, otaczające wyrażenia i specyfikacje formatowania.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. Interpolowane wyrażenie ciągu jest wynikiem interpolated_string_literal , który został podzielony na poszczególne tokeny, zgodnie z opisem w interpolowanych literałach ciągu.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 w interpolacji musi mieć niejawną konwersję, aby int.The constant_expression in an interpolation must have an implicit conversion to int.

Interpolated_string_expression jest klasyfikowany jako wartość.An interpolated_string_expression is classified as a value. Jeśli jest on natychmiast konwertowany na System.IFormattable lub System.FormattableString z niejawną konwersją ciągu (niejawnymi konwersji ciągów), interpolowane wyrażenie ciągu ma ten typ.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. W przeciwnym razie ma typ string.Otherwise, it has the type string.

Jeśli typ ciągu interpolowanego jest System.IFormattable lub System.FormattableString, znaczenie jest wywołanie 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. Jeśli typ jest string, znaczenie wyrażenia jest wywołaniem string.Format.If the type is string, the meaning of the expression is a call to string.Format. W obu przypadkach lista argumentów wywołania składa się z literału ciągu formatu z symbolami zastępczymi dla każdej interpolacji oraz argumentu dla każdego wyrażenia odpowiadającego posiadaczom miejsc.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.

Literał ciągu formatu jest skonstruowany w następujący sposób, gdzie N jest liczbą interpolacji w interpolated_string_expression:The format string literal is constructed as follows, where N is the number of interpolations in the interpolated_string_expression:

  • Jeśli interpolated_regular_string_whole lub interpolated_verbatim_string_whole następuje po znaku $, literał ciągu formatu jest tym tokenem.If an interpolated_regular_string_whole or an interpolated_verbatim_string_whole follows the $ sign, then the format string literal is that token.
  • W przeciwnym razie literał ciągu formatu składa się z:Otherwise, the format string literal consists of:
    • Najpierw interpolated_regular_string_start lub interpolated_verbatim_string_startFirst the interpolated_regular_string_start or interpolated_verbatim_string_start
    • Następnie dla każdej liczby I od 0 do N-1:Then for each number I from 0 to N-1:
      • Reprezentacja dziesiętna IThe decimal representation of I
      • Następnie, Jeśli odpowiednia Interpolacja ma constant_expression, , (przecinek), a następnie dziesiętną reprezentację wartości constant_expressionThen, if the corresponding interpolation has a constant_expression, a , (comma) followed by the decimal representation of the value of the constant_expression
      • Następnie interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid lub interpolated_verbatim_string_end bezpośrednio po odpowiednim interpolce.Then the interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid or interpolated_verbatim_string_end immediately following the corresponding interpolation.

Kolejne argumenty są po prostu wyrażeniami z interpolacji (jeśli istnieją) w kolejności.The subsequent arguments are simply the expressions from the interpolations (if any), in order.

Do zrobienia: przykłady.TODO: examples.

Proste nazwySimple names

Simple_name składa się z identyfikatora, opcjonalnie po którym następuje lista argumentów typu:A simple_name consists of an identifier, optionally followed by a type argument list:

simple_name
    : identifier type_argument_list?
    ;

Simple_name ma postać I lub formularza I<A1,...,Ak>, gdzie I jest pojedynczym identyfikatorem, a <A1,...,Ak> jest opcjonalny 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. Gdy nie określono type_argument_list , należy wziąć pod uwagę K wartość zero.When no type_argument_list is specified, consider K to be zero. Simple_name jest oceniane i sklasyfikowane w następujący sposób:The simple_name is evaluated and classified as follows:

  • Jeśli K jest równa zero, a simple_name pojawia się w bloku , a jeśli blok(lub otaczający blok) obszar deklaracji zmiennych lokalnych (deklaracji) zawiera zmienną lokalną, parametr lub stałą z nazwą I, wówczas simple_name odwołuje się do tej zmiennej lokalnej, parametru lub stałej i jest sklasyfikowana jako zmienna lub wartość.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.

  • Jeśli K ma wartość zero, a simple_name pojawia się w treści deklaracji metody ogólnej i jeśli ta deklaracja zawiera parametr typu o nazwie I, simple_name odwołuje się do tego parametru typu.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.

  • W przeciwnym razie dla każdego typu wystąpienia T (Typ wystąpienia), rozpoczynając od typu wystąpienia, bezpośrednio otaczającą deklarację typu i kontynuując typ wystąpienia każdej klasy lub deklaracji struktury (jeśli istnieje):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):

    • Jeśli K ma wartość zero, a deklaracja T zawiera parametr typu o nazwie I, wówczas simple_name odwołuje się do tego parametru typu.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.
    • W przeciwnym razie, jeśli odnośnik elementu członkowskiego (odnośnik elementów członkowskich) I w T z argumentami typu  Kgeneruje dopasowanie:Otherwise, if a member lookup (Member lookup) of I in T with K type arguments produces a match:
      • Jeśli T jest typem wystąpienia bezpośrednio otaczającej klasy lub typu struktury, a odnośnik identyfikuje jedną lub więcej metod, wynik jest grupą metod ze skojarzonym wyrażeniem wystąpienia 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. Jeśli określono listę argumentów typu, jest ona używana w wywołaniu metody ogólnej (wywołania metody).If a type argument list was specified, it is used in calling a generic method (Method invocations).
      • W przeciwnym razie, jeśli T jest typem wystąpienia bezpośrednio otaczającej klasy lub typu struktury, jeśli wyszukiwanie identyfikuje element członkowski wystąpienia, a jeśli odwołanie występuje w treści konstruktora wystąpienia, metody wystąpienia lub akcesora wystąpienia, wynik jest taki sam jak dostęp doelementu członkowskiegow formularzu 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. Może się to zdarzyć tylko wtedy, gdy K wynosi zero.This can only happen when K is zero.
      • W przeciwnym razie wynik jest taki sam jak dostęp do elementu członkowskiego (dostęp do elementu członkowskiego) formularza T.I lub 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>. W tym przypadku jest to błąd czasu powiązania dla simple_name , aby odwołać się do elementu członkowskiego wystąpienia.In this case, it is a binding-time error for the simple_name to refer to an instance member.
  • W przeciwnym razie dla każdej przestrzeni nazw N, rozpoczynając od przestrzeni nazw, w której występuje simple_name , kontynuując z każdą otaczającą przestrzenią nazw (jeśli istnieje) i kończącą się globalną przestrzenią nazw, następujące kroki są oceniane do momentu zlokalizowania jednostki: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:

    • Jeśli K ma wartość zero, a I to nazwa przestrzeni nazw w N, wówczas:If K is zero and I is the name of a namespace in N, then:
      • Jeśli lokalizacja, w której występuje simple_name , jest ujęta w deklarację przestrzeni nazw dla N, a Deklaracja przestrzeni nazw zawiera extern_alias_directive lub using_alias_directive , która kojarzy nazwę I z przestrzenią nazw lub typem, wówczas simple_name jest niejednoznaczna i wystąpi błąd w czasie kompilacji.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.
      • W przeciwnym razie simple_name odwołuje się do przestrzeni nazw o nazwie I w N.Otherwise, the simple_name refers to the namespace named I in N.
    • W przeciwnym razie, jeśli N zawiera dostępny typ o nazwie I i Kparametrów typu  , wówczas:Otherwise, if N contains an accessible type having name I and K type parameters, then:
      • Jeśli K ma wartość zero, a lokalizacja, w której występuje simple_name , jest ujęta w deklarację przestrzeni nazw dla N a Deklaracja przestrzeni nazw zawiera extern_alias_directive lub using_alias_directive , który kojarzy nazwę I z przestrzenią nazw lub typem, wówczas simple_name jest niejednoznaczna i wystąpi błąd kompilacji.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.
      • W przeciwnym razie namespace_or_type_name odwołuje się do typu złożonego za pomocą podanych argumentów typu.Otherwise, the namespace_or_type_name refers to the type constructed with the given type arguments.
    • W przeciwnym razie, jeśli lokalizacja, w której występuje simple_name , jest ujęta w deklarację przestrzeni nazw dla N:Otherwise, if the location where the simple_name occurs is enclosed by a namespace declaration for N:
      • Jeśli K ma wartość zero, a Deklaracja przestrzeni nazw zawiera extern_alias_directive lub using_alias_directive , które kojarzą nazwę I z zaimportowaną przestrzenią nazw lub typem, wówczas simple_name odwołuje się do tej przestrzeni nazw lub typu.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.
      • W przeciwnym razie, jeśli przestrzenie nazw i deklaracje typów zaimportowane przez using_namespace_directives i using_static_directives deklaracji przestrzeni nazw zawierają dokładnie jeden dostępny typ lub statyczny element członkowski, który ma nazwę I i K parametry typu, a następnie simple_name odwołuje się do tego typu lub elementu członkowskiego skonstruowanego za pomocą podanych argumentów typu.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.
      • W przeciwnym razie, jeśli przestrzenie nazw i typy zaimportowane przez using_namespace_directives deklaracji przestrzeni nazw zawierają więcej niż jeden statyczny element członkowski typu lub nierozszerzającej metody o nazwie I i K parametrów typu, wówczas simple_name jest niejednoznaczna i wystąpi błąd.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.

    Należy zauważyć, że cały krok jest ściśle równoległy do odpowiedniego kroku w przetwarzaniu namespace_or_type_name (nazw i typów).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).

  • W przeciwnym razie simple_name jest niezdefiniowana i wystąpi błąd w czasie kompilacji.Otherwise, the simple_name is undefined and a compile-time error occurs.

Wyrażenia w nawiasachParenthesized expressions

Parenthesized_expression składa się z wyrażenia ujętego w nawiasy.A parenthesized_expression consists of an expression enclosed in parentheses.

parenthesized_expression
    : '(' expression ')'
    ;

Parenthesized_expression jest oceniane przez obliczenie wyrażenia w nawiasach.A parenthesized_expression is evaluated by evaluating the expression within the parentheses. Jeśli wyrażenie w nawiasach oznacza przestrzeń nazw lub typ, wystąpi błąd w czasie kompilacji.If the expression within the parentheses denotes a namespace or type, a compile-time error occurs. W przeciwnym razie wynik parenthesized_expression jest wynikiem obliczenia zawartego wyrażenia.Otherwise, the result of the parenthesized_expression is the result of the evaluation of the contained expression.

Dostęp do elementu członkowskiegoMember access

Member_access składa się z primary_expression, predefined_typelub qualified_alias_member, po którym następuje token ".", po którym następuje Identyfikator, opcjonalnie po którym następuje 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 produkcyjne jest definiowana w kwalifikatorach aliasów przestrzeni nazw.The qualified_alias_member production is defined in Namespace alias qualifiers.

Member_access ma postać E.I lub formularza E.I<A1, ..., Ak>, gdzie E jest wyrażeniem podstawowym, I jest pojedynczym identyfikatorem, a <A1, ..., Ak> jest opcjonalną 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. Gdy nie określono type_argument_list , należy wziąć pod uwagę K wartość zero.When no type_argument_list is specified, consider K to be zero.

Member_access z primary_expressionem typu dynamic jest dynamicznie powiązany (powiązanie dynamiczne).A member_access with a primary_expression of type dynamic is dynamically bound (Dynamic binding). W takim przypadku kompilator klasyfikuje dostęp do elementu członkowskiego jako dostęp do właściwości typu dynamic.In this case the compiler classifies the member access as a property access of type dynamic. Poniższe reguły do określenia znaczenia member_access są następnie stosowane w czasie wykonywania przy użyciu typu czasu wykonywania, a nie typu czasu kompilacji 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. Jeśli ta Klasyfikacja czasu wykonywania prowadzi do grupy metod, dostęp do elementu członkowskiego musi być 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 jest oceniane i sklasyfikowane w następujący sposób:The member_access is evaluated and classified as follows:

  • Jeśli K ma wartość zero, a E jest przestrzenią nazw, a E zawiera zagnieżdżoną przestrzeń nazw o nazwie I, wynik jest tą przestrzenią nazw.If K is zero and E is a namespace and E contains a nested namespace with name I, then the result is that namespace.
  • W przeciwnym razie, jeśli E jest przestrzenią nazw i E zawiera dostępny typ o nazwie I i K typ, a następnie wynik jest typem skonstruowanym z podanym argumentem typu.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.
  • Jeśli E jest predefined_type lub primary_expression sklasyfikowane jako typ, jeśli E nie jest parametrem typu, a w przypadku wyszukania elementu członkowskiego (odnośnik elementu członkowskiego) I w E z K parametry typu są generowane dopasowanie, E.I zostanie obliczone i sklasyfikowane w następujący sposób: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:
    • Jeśli I identyfikuje typ, wynik jest typem skonstruowanym z podanym argumentem typu.If I identifies a type, then the result is that type constructed with the given type arguments.
    • Jeśli I identyfikuje jedną lub więcej metod, wynik jest grupą metod bez skojarzonego wyrażenia wystąpienia.If I identifies one or more methods, then the result is a method group with no associated instance expression. Jeśli określono listę argumentów typu, jest ona używana w wywołaniu metody ogólnej (wywołania metody).If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Jeśli I identyfikuje właściwość static, wynik jest dostęp do właściwości bez skojarzonego wyrażenia wystąpienia.If I identifies a static property, then the result is a property access with no associated instance expression.
    • Jeśli I identyfikuje pole static:If I identifies a static field:
      • Jeśli pole jest readonly i odwołanie występuje poza statycznym konstruktorem klasy lub struktury, w której jest zadeklarowane pole, wynik jest wartością, a mianowicie wartość pola statycznego IE.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.
      • W przeciwnym razie wynik jest zmienną, a mianowicie pole statyczne IE.Otherwise, the result is a variable, namely the static field I in E.
    • Jeśli I identyfikuje zdarzenie static:If I identifies a static event:
      • Jeśli odwołanie występuje w klasie lub strukturze, w której zdarzenie jest zadeklarowane, a zdarzenie zostało zadeklarowane bez event_accessor_declarations (zdarzenia), E.I jest przetwarzane dokładnie tak, jakby I było polem statycznym.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.
      • W przeciwnym razie wynik jest dostęp do zdarzenia bez skojarzonego wyrażenia wystąpienia.Otherwise, the result is an event access with no associated instance expression.
    • Jeśli I identyfikuje stałą, wynik jest wartością, a mianowicie wartością tej stałej.If I identifies a constant, then the result is a value, namely the value of that constant.
    • Jeśli I identyfikuje element członkowski wyliczenia, wynik jest wartością, a mianowicie wartością tego elementu członkowskiego wyliczenia.If I identifies an enumeration member, then the result is a value, namely the value of that enumeration member.
    • W przeciwnym razie E.I jest nieprawidłowym odwołaniem do elementu członkowskiego i wystąpi błąd w czasie kompilacji.Otherwise, E.I is an invalid member reference, and a compile-time error occurs.
  • Jeśli E jest dostęp do właściwości, indeksatora, zmienna lub wartość, typ T, a odnośnik elementu członkowskiego (odnośnik elementów członkowskich) I w T z Kargumenty typu  da dopasowanie, a następnie E.I zostanie obliczone i sklasyfikowane w następujący sposób: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:
    • Po pierwsze, jeśli E jest dostęp do właściwości lub indeksatora, zostanie uzyskana wartość dostępu właściwości lub indeksatora (wartości wyrażeń), a E zostanie przeliczona jako wartość.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.
    • Jeśli I identyfikuje jedną lub więcej metod, wynik jest grupą metod ze skojarzonym wyrażeniem wystąpienia E.If I identifies one or more methods, then the result is a method group with an associated instance expression of E. Jeśli określono listę argumentów typu, jest ona używana w wywołaniu metody ogólnej (wywołania metody).If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Jeśli I identyfikuje Właściwość wystąpienia,If I identifies an instance property,
      • Jeśli E jest this, I identyfikuje automatycznie implementowaną Właściwość (automatycznie implementowane właściwości) bez metody ustawiającej, a odwołanie występuje w konstruktorze wystąpienia dla klasy lub typu struktury T, a następnie wynik to zmienna, a mianowicie ukryte pole zapasowe dla właściwości automatycznej podaną przez I w wystąpieniu T podanym przez 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.
      • W przeciwnym razie wynik jest dostęp do właściwości ze skojarzonym wyrażeniem wystąpienia E.Otherwise, the result is a property access with an associated instance expression of E.
    • Jeśli T jest class_type i I identyfikuje pole wystąpienia tego class_type:If T is a class_type and I identifies an instance field of that class_type:
      • Jeśli wartość E jest null, zostanie zgłoszony System.NullReferenceException.If the value of E is null, then a System.NullReferenceException is thrown.
      • W przeciwnym razie, jeśli pole jest readonly i odwołanie występuje poza konstruktorem wystąpienia klasy, w której jest zadeklarowane pole, wynik jest wartością, a mianowicie wartość pola I w obiekcie, do którego odwołuje się 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.
      • W przeciwnym razie wynik jest zmienną, a mianowicie pola I w obiekcie, do którego odwołuje się E.Otherwise, the result is a variable, namely the field I in the object referenced by E.
    • Jeśli T jest struct_type i I identyfikuje pole wystąpienia tego struct_type:If T is a struct_type and I identifies an instance field of that struct_type:
      • Jeśli E jest wartością lub jeśli pole jest readonly i odwołanie występuje poza konstruktorem wystąpienia struktury, w którym jest zadeklarowane pole, wynik jest wartością, a mianowicie wartość pola I w wystąpieniu struktury podanym przez 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.
      • W przeciwnym razie wynik jest zmienną, a mianowicie pola I w wystąpieniu struktury podanym przez E.Otherwise, the result is a variable, namely the field I in the struct instance given by E.
    • Jeśli I identyfikuje zdarzenie wystąpienia:If I identifies an instance event:
      • Jeśli odwołanie występuje w klasie lub strukturze, w której zdarzenie jest zadeklarowane, a zdarzenie zostało zadeklarowane bez event_accessor_declarations (zdarzenia), a odwołanie nie występuje po lewej stronie operatora += lub -=, a następnie E.I jest przetwarzane dokładnie tak, jakby I było polem wystąpienia.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.
      • W przeciwnym razie wynikiem jest dostęp do zdarzenia ze skojarzonym wyrażeniem wystąpienia E.Otherwise, the result is an event access with an associated instance expression of E.
  • W przeciwnym razie podjęto próbę przetworzenia E.I jako wywołania metody rozszerzenia (wywołania metody rozszerzenia).Otherwise, an attempt is made to process E.I as an extension method invocation (Extension method invocations). Jeśli to się nie powiedzie, E.I jest nieprawidłowym odwołaniem do elementu członkowskiego i wystąpi błąd w czasie powiązania.If this fails, E.I is an invalid member reference, and a binding-time error occurs.

Identyczne nazwy proste i nazwy typówIdentical simple names and type names

W celu uzyskania dostępu do elementu członkowskiego w formularzu E.I, jeśli E jest pojedynczym identyfikatorem, a znaczenie E jako simple_name (proste nazwy) to stała, pole, właściwość, zmienna lokalna lub parametr z tym samym typem, co znaczenie E jako TYPE_NAME (nazwa przestrzeni nazw i typów), a następnie oba możliwe znaczenia E są dozwolone.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. Dwa możliwe znaczenia E.I nigdy nie są niejednoznaczne, ponieważ I musi być elementem członkowskim typu E w obu przypadkach.The two possible meanings of E.I are never ambiguous, since I must necessarily be a member of the type E in both cases. Innymi słowy, reguła po prostu zezwala na dostęp do statycznych elementów członkowskich i zagnieżdżonych typów E, w których wystąpił błąd kompilacji.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. Na przykład: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
    }
}

Niejasności gramatykiGrammar ambiguities

Produkcje dla simple_name (prostych nazw) i member_access (dostęp do elementów członkowskich) mogą dać podstawę niejasności w gramatyki.The productions for simple_name (Simple names) and member_access (Member access) can give rise to ambiguities in the grammar for expressions. Na przykład, instrukcja:For example, the statement:

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

może być interpretowany jako wywołanie F z dwoma argumentami, G < A i B > (7).could be interpreted as a call to F with two arguments, G < A and B > (7). Alternatywnie, można go interpretować jako wywołanie do F z jednym argumentem, który jest wywołaniem metody generycznej G z dwoma argumentami typu i jednym argumentem regularnym.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.

Jeśli sekwencja tokenów może być analizowana (w kontekście) jako simple_name (proste nazwy), member_access (dostęp do elementu członkowskiego) lub pointer_member_access (wskaźnik dostępu do składowych) kończące się type_argument_list (argumentami typu), zostaje sprawdzony token bezpośrednio po zamykającym tokenie >.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. Jeśli jest to jedna zIf it is one of

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

następnie type_argument_list jest zachowywany jako część simple_name, member_access lub pointer_member_access i wszelkie inne możliwe przeanalizowanie sekwencji tokenów jest odrzucane.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. W przeciwnym razie type_argument_list nie jest uważana za część simple_name, member_access lub pointer_member_access, nawet jeśli nie istnieje żadna inna możliwa analiza sekwencji tokenów.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. Należy pamiętać, że te reguły nie są stosowane podczas analizowania type_argument_list w namespace_or_type_name (nazwy przestrzeni nazw i typów).Note that these rules are not applied when parsing a type_argument_list in a namespace_or_type_name (Namespace and type names). InstrukcjaThe statement

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

zgodnie z tą regułą, należy interpretować jako wywołanie F z jednym argumentem, który jest wywołaniem metody generycznej G z dwoma argumentami typu i jednym argumentem regularnym.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. InstrukcjeThe statements

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

Każdy z nich będzie interpretowany jako wywołanie F z dwoma argumentami.will each be interpreted as a call to F with two arguments. InstrukcjaThe statement

x = F < A > +y;

będzie interpretowany jako operator mniejszości, operator większości, i jednoargumentowy operator plus, tak jakby instrukcja była zapisywana x = (F < A) > (+y), a nie jako simple_name z type_argument_list po którym następuje operator binarny Plus.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. W instrukcjiIn the statement

x = y is C<T> + z;

tokeny C<T> są interpretowane jako namespace_or_type_name z type_argument_list.the tokens C<T> are interpreted as a namespace_or_type_name with a type_argument_list.

Wyrażenia wywołaniaInvocation expressions

Invocation_expression jest używany do wywołania metody.An invocation_expression is used to invoke a method.

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

Invocation_expression jest powiązany dynamicznie (powiązanie dynamiczne), jeśli co najmniej jedna z następujących posiada:An invocation_expression is dynamically bound (Dynamic binding) if at least one of the following holds:

  • Primary_expression ma dynamictypu czasu kompilacji.The primary_expression has compile-time type dynamic.
  • Co najmniej jeden argument opcjonalnej argument_list ma typ czasu kompilacji dynamic, a primary_expression nie ma typu delegata.At least one argument of the optional argument_list has compile-time type dynamic and the primary_expression does not have a delegate type.

W takim przypadku kompilator klasyfikuje invocation_expression jako wartość typu dynamic.In this case the compiler classifies the invocation_expression as a value of type dynamic. Poniższe reguły do określenia znaczenia invocation_expression są następnie stosowane w czasie wykonywania, przy użyciu typu czasu wykonywania, a nie typu czasu kompilacji dla primary_expression i argumentów, które mają dynamictypu czasu kompilacji.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. Jeśli primary_expression nie ma dynamictypu czasu kompilacji, wywołanie metody przejdzie do ograniczonego sprawdzenia czasu kompilacji zgodnie z opisem w sprawdzaniu poprawności dynamicznego rozpoznawania przeciążenia w czasie kompilacji.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 musi być grupą metod lub wartością delegate_type.The primary_expression of an invocation_expression must be a method group or a value of a delegate_type. Jeśli primary_expression jest grupą metod, invocation_expression jest wywołaniem metody (wywołania metody).If the primary_expression is a method group, the invocation_expression is a method invocation (Method invocations). Jeśli primary_expression jest wartością delegate_type, invocation_expression jest wywołaniem delegata (Delegaty wywołań).If the primary_expression is a value of a delegate_type, the invocation_expression is a delegate invocation (Delegate invocations). Jeśli primary_expression nie jest grupą metod ani wartością delegate_type, wystąpi błąd w czasie trwania powiązania.If the primary_expression is neither a method group nor a value of a delegate_type, a binding-time error occurs.

Opcjonalne argument_list (listy argumentów) zawierają wartości lub odwołania do zmiennych dla parametrów metody.The optional argument_list (Argument lists) provides values or variable references for the parameters of the method.

Wyniki oceny invocation_expression są klasyfikowane w następujący sposób:The result of evaluating an invocation_expression is classified as follows:

  • Jeśli invocation_expression wywołuje metodę lub delegata, która zwraca void, wynik nie będzie miał wartości Nothing.If the invocation_expression invokes a method or delegate that returns void, the result is nothing. Wyrażenie sklasyfikowane jako Nothing nie jest dozwolone tylko w kontekście statement_expression (instrukcji wyrażenia) ani jako treści lambda_expression (wyrażenia funkcji anonimowych).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). W przeciwnym razie wystąpi błąd w czasie powiązania.Otherwise a binding-time error occurs.
  • W przeciwnym razie wynik jest wartością typu zwracanego przez metodę lub delegat.Otherwise, the result is a value of the type returned by the method or delegate.

Wywołania metodyMethod invocations

W przypadku wywołania metody primary_expression invocation_expression musi być grupą metod.For a method invocation, the primary_expression of the invocation_expression must be a method group. Grupa metod identyfikuje jedną metodę do wywołania lub zestaw przeciążonych metod, z których można wybrać konkretną metodę do wywołania.The method group identifies the one method to invoke or the set of overloaded methods from which to choose a specific method to invoke. W tym ostatnim przypadku określenie konkretnej metody do wywołania jest zależne od kontekstu dostarczonego przez typy argumentów w 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.

Przetwarzanie w czasie powiązania metody wywołania metod M(A), gdzie M jest grupą metod (może także dotyczyć type_argument_list), a A jest opcjonalne argument_list, składa się z następujących kroków: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:

  • Zestaw metod kandydujących dla wywołania metody jest konstruowany.The set of candidate methods for the method invocation is constructed. Dla każdej metody F skojarzonej z grupą metod M:For each method F associated with the method group M:
    • Jeśli F nie jest ogólny, F jest kandydatem, gdy:If F is non-generic, F is a candidate when:
    • Jeśli F jest ogólny i M nie ma listy argumentów typu, F jest kandydatem, gdy:If F is generic and M has no type argument list, F is a candidate when:
      • Wnioskowanie o typie (wnioskowanie o typie) kończy się powodzeniem, wnioskowanie listy argumentów typu dla wywołania iType inference (Type inference) succeeds, inferring a list of type arguments for the call, and
      • Gdy argumenty typu wywnioskowane zostaną zastąpione odpowiednimi parametrami typu metody, wszystkie skompilowane typy na liście parametrów F spełniają ich ograniczenia (spełniające warunki ograniczające), a lista parametrów F ma zastosowanie w odniesieniu do A (odpowiedni element członkowski funkcji).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).
    • Jeśli F jest ogólny i M zawiera listę argumentów typu, F jest kandydatem, gdy:If F is generic and M includes a type argument list, F is a candidate when:
      • F ma taką samą liczbę parametrów typu metody jak podano na liście argumentów typu.F has the same number of method type parameters as were supplied in the type argument list, and
      • Gdy argumenty typu są zastępowane odpowiednimi parametrami typu metody, wszystkie skompilowane typy na liście parametrów F spełniają ich ograniczenia (spełniające ograniczenia), a lista parametrów F ma zastosowanie w odniesieniu do A (odpowiedni element członkowski funkcji).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).
  • Zestaw metod kandydujących jest zredukowany, aby zawierał tylko metody z najbardziej pochodnych typów: dla każdej metody C.F w zestawie, gdzie C jest typem, w którym Metoda F jest zadeklarowana, wszystkie metody zadeklarowane w typie podstawowym C są usuwane z zestawu.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. Ponadto jeśli C jest typem klasy innym niż object, wszystkie metody zadeklarowane w typie interfejsu są usuwane z zestawu.Furthermore, if C is a class type other than object, all methods declared in an interface type are removed from the set. (Ta ostatnia reguła ma wpływ tylko wtedy, gdy grupa metod była wynikiem przeszukiwania elementu członkowskiego w parametrze typu mającym obowiązującą klasę bazową inną niż obiekt i niepusty zestaw obowiązujących interfejsów).(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.)
  • Jeśli wynikający z tego zestaw metod kandydujących jest pusty, dalsze przetwarzanie w poniższych krokach zostanie porzucone, a zamiast tego zostanie podjęta próba przetworzenia wywołania jako wywołania metody rozszerzenia (wywołania metody rozszerzenia).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). Jeśli to się nie powiedzie, żadne odpowiednie metody nie istnieją i wystąpi błąd w czasie powiązania.If this fails, then no applicable methods exist, and a binding-time error occurs.
  • Najlepsza Metoda zestawu metod kandydujących jest identyfikowana przy użyciu reguł rozpoznawania przeciążenia.The best method of the set of candidate methods is identified using the overload resolution rules of Overload resolution. Jeśli nie można zidentyfikować pojedynczej metody, wywołanie metody jest niejednoznaczne i występuje błąd w czasie powiązania.If a single best method cannot be identified, the method invocation is ambiguous, and a binding-time error occurs. Podczas rozpoznawania przeciążenia parametry metody ogólnej są brane pod uwagę po podstawianiu argumentów typu (dostarczonych lub wywnioskowanych) dla odpowiednich parametrów typu metody.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.
  • Zostanie wykonana ostateczna weryfikacja wybranej najlepszej metody:Final validation of the chosen best method is performed:
    • Metoda jest weryfikowana w kontekście grupy metod: Jeśli najlepsza metoda jest metodą statyczną, Grupa metod musi mieć wynik simple_name lub member_access za pośrednictwem typu.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. Jeśli najlepsza metoda jest metodą wystąpienia, Grupa metod musi mieć wynik simple_name, member_access za pomocą zmiennej lub wartości lub 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. Jeśli żaden z tych wymagań nie ma wartości true, wystąpi błąd w czasie trwania powiązania.If neither of these requirements is true, a binding-time error occurs.
    • Jeśli najlepsza metoda jest metodą rodzajową, argumenty typu (dostarczone lub wywnioskowane) są sprawdzane względem ograniczeń (spełnianie ograniczeń) zadeklarowanych dla metody ogólnej.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. Jeśli którykolwiek z argumentów typu nie spełnia odpowiednich ograniczeń w parametrze typu, wystąpi błąd w czasie powiązania.If any type argument does not satisfy the corresponding constraint(s) on the type parameter, a binding-time error occurs.

Po wybraniu metody i sprawdzeniu jej pod kątem czasu wiązania przez powyższe kroki, rzeczywiste wywołanie w czasie wykonywania jest przetwarzane zgodnie z regułami wywołania elementu członkowskiego, które opisano w sprawdzeniu czasu kompilacji dynamicznego rozpoznawania przeciążenia.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.

Intuicyjny efekt opisanych powyżej reguł rozpoznawania jest następujący: aby zlokalizować konkretną metodę wywoływaną przez wywołanie metody, należy rozpocząć od typu wskazanego przez wywołanie metody i przetworzyć łańcuch dziedziczenia do momentu, gdy ma to zastosowanie do co najmniej jednego, znaleziono dostępną deklarację metody niezastępującej.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. Następnie należy wykonać wnioskowanie o typie i metodę rozpoznawania przeciążenia dla zestawu odpowiednich, dostępnych, zastąpień metod zadeklarowanych w tym typie i wywoływać metody w ten sposób.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. Jeśli żadna metoda nie została znaleziona, spróbuj zamiast tego przetworzyć wywołanie jako wywołanie metody rozszerzenia.If no method was found, try instead to process the invocation as an extension method invocation.

Wywołania metody rozszerzeniaExtension method invocations

W wywołaniu metody (wywołania w zapakowanych wystąpieniach) jednego z formularzyIn a method invocation (Invocations on boxed instances) of one of the forms

expr . identifier ( )

expr . identifier ( args )

expr . identifier < typeargs > ( )

expr . identifier < typeargs > ( args )

Jeśli normalne przetwarzanie wywołania nie odnajdzie odpowiednich metod, podejmowana jest próba przetworzenia konstrukcji jako wywołania metody rozszerzenia.if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. Jeśli wyrażenie lub którykolwiek z argumentów ma dynamictypu czasu kompilacji, metody rozszerzające nie będą miały zastosowania.If expr or any of the args has compile-time type dynamic, extension methods will not apply.

Celem jest znalezienie najlepszego type_name C, dzięki czemu można wykonać odpowiednie wywołanie metody statycznej: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 )

Metoda rozszerzająca Ci.Mj kwalifikuje się, jeśli:An extension method Ci.Mj is eligible if:

  • Ci jest klasą nieogólną, niezagnieżdżonąCi is a non-generic, non-nested class
  • Nazwa Mj jest identyfikatoremThe name of Mj is identifier
  • Mj jest dostępne i stosowane w przypadku zastosowania do argumentów jako metody statycznej, jak pokazano powyżejMj is accessible and applicable when applied to the arguments as a static method as shown above
  • Niejawna tożsamość, odwołanie lub zamiana opakowania istnieje z wyrażenia do typu pierwszego parametru Mj.An implicit identity, reference or boxing conversion exists from expr to the type of the first parameter of Mj.

Wyszukiwanie C odbywa się w następujący sposób:The search for C proceeds as follows:

  • Począwszy od najbliższej deklaracji przestrzeni nazw, kontynuując każdą zachodzącą deklarację przestrzeni nazw i kończącą się jednostką kompilacji, kolejne próby są wykonywane w celu znalezienia kandydującego zestawu metod rozszerzających: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:
    • Jeśli dana przestrzeń nazw lub jednostka kompilacji bezpośrednio zawiera deklaracje typu nieogólnego Ci z uprawnionymi metodami rozszerzenia Mj, zestaw tych metod rozszerzających jest zestaw kandydatów.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.
    • Jeśli typy Ci zaimportowane przez using_static_declarations i bezpośrednio zadeklarowane w przestrzeniach nazw zaimportowanych przez using_namespace_directives w danej przestrzeni nazw lub jednostce kompilacji, bezpośrednio zawierają kwalifikujące się metody rozszerzenia Mj, wówczas zestaw tych metod rozszerzających jest zestaw kandydatów.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.
  • Jeśli w żadnej deklaracji przestrzeni nazw lub jednostce kompilacji nie zostanie znaleziony zestaw kandydatów, wystąpi błąd w czasie kompilacji.If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs.
  • W przeciwnym razie Rozpoznanie przeciążenia jest stosowane do zestawu kandydatów zgodnie z opisem w (rozpoznawanie przeciążenia).Otherwise, overload resolution is applied to the candidate set as described in (Overload resolution). Jeśli nie zostanie znaleziona żadna Najlepsza Metoda, wystąpi błąd w czasie kompilacji.If no single best method is found, a compile-time error occurs.
  • C jest typem, w ramach którego Najlepsza Metoda jest zadeklarowana jako Metoda rozszerzenia.C is the type within which the best method is declared as an extension method.

Przy użyciu C jako obiektu docelowego wywołanie metody jest następnie przetwarzane jako wywołanie metody statycznej (sprawdzanie wczasie kompilacji dynamicznego rozpoznawania przeciążenia).Using C as a target, the method call is then processed as a static method invocation (Compile-time checking of dynamic overload resolution).

Powyższe zasady oznaczają, że metody wystąpień mają pierwszeństwo przed metodami rozszerzania, te metody rozszerzające dostępne w deklaracji wewnętrznej przestrzeni nazw mają pierwszeństwo przed metodami rozszerzenia dostępnymi w deklaracjach zewnętrznych przestrzeni nazw i tym rozszerzeniu Metody zadeklarowane bezpośrednio w przestrzeni nazw mają pierwszeństwo przed metodami rozszerzenia importowanymi do tej samej przestrzeni nazw za pomocą dyrektywy using Namespace.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. Na przykład: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)
    }
}

W przykładzie metoda Bma pierwszeństwo przed pierwszą metodą rozszerzenia, a metoda Cma pierwszeństwo przed obiema metodami rozszerzenia.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();
        }
    }
}

Dane wyjściowe tego przykładu to:The output of this example is:

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

D.G ma pierwszeństwo przed C.G, a E.F ma pierwszeństwo przed D.F i C.F.D.G takes precedence over C.G, and E.F takes precedence over both D.F and C.F.

Delegowanie wywołańDelegate invocations

Dla wywołania delegata primary_expression invocation_expression musi być wartością delegate_type.For a delegate invocation, the primary_expression of the invocation_expression must be a value of a delegate_type. Co więcej, biorąc pod uwagę delegate_type być elementem członkowskim funkcji z tą samą listą parametrów co delegate_type, Delegate_type musi mieć zastosowanie (odpowiedni element członkowski funkcji) w odniesieniu do 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.

Przetwarzanie w czasie wykonywania delegata wywołania formularza D(A), gdzie D jest primary_expression delegate_type i A jest opcjonalne argument_list, składa się z następujących kroków: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 jest oceniane.D is evaluated. Jeśli ta Ocena spowoduje wyjątek, nie są wykonywane żadne dalsze kroki.If this evaluation causes an exception, no further steps are executed.
  • Wartość D jest sprawdzana jako prawidłowa.The value of D is checked to be valid. Jeśli wartość D jest null, zostanie zgłoszony System.NullReferenceException i nie zostaną wykonane żadne dalsze kroki.If the value of D is null, a System.NullReferenceException is thrown and no further steps are executed.
  • W przeciwnym razie D jest odwołaniem do wystąpienia delegata.Otherwise, D is a reference to a delegate instance. Wywołania elementu członkowskiego funkcji (Sprawdzanie w czasie kompilacji dynamicznego rozpoznawania przeciążenia) są wykonywane na każdej z wywoływanych jednostek na liście wywołań delegata.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. W przypadku wywoływanych jednostek składających się z wystąpienia i metody wystąpienia wystąpienie dla wywołania jest wystąpieniem zawartym w jednostce, którą można wywołać.For callable entities consisting of an instance and instance method, the instance for the invocation is the instance contained in the callable entity.

Dostęp do elementuElement access

Element_access składa się z primary_no_array_creation_expression, po którym następuje token "[", po którym następuje argument_list, po którym następuje 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 składa się z jednego lub więcej argumentóws, rozdzielonych przecinkami.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 nie może zawierać argumentów ref lub out.The argument_list of an element_access is not allowed to contain ref or out arguments.

Element_access jest powiązany dynamicznie (powiązanie dynamiczne), jeśli co najmniej jedna z następujących posiada:An element_access is dynamically bound (Dynamic binding) if at least one of the following holds:

  • Primary_no_array_creation_expression ma dynamictypu czasu kompilacji.The primary_no_array_creation_expression has compile-time type dynamic.
  • Co najmniej jedno wyrażenie argument_list ma typ czasu kompilacji dynamic, a primary_no_array_creation_expression nie ma typu tablicy.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.

W takim przypadku kompilator klasyfikuje element_access jako wartość typu dynamic.In this case the compiler classifies the element_access as a value of type dynamic. Poniższe reguły do określenia znaczenia element_access są następnie stosowane w czasie wykonywania, przy użyciu typu czasu wykonywania, a nie typu czasu kompilacji dla primary_no_array_creation_expression i argument_list wyrażeń, które mają dynamictypu czasu kompilacji.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. Jeśli primary_no_array_creation_expression nie ma dynamictypu czasu kompilacji, dostęp do elementu jest poddawany ograniczonemu sprawdzeniu czasu kompilacji, zgodnie z opisem w sprawdzeniu poprawności dynamicznego rozpoznawania przeciążenia.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.

Jeśli primary_no_array_creation_expression element_access jest wartością array_type, element_access jest dostęp do tablicy (dostęp do tablicy).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). W przeciwnym razie primary_no_array_creation_expression musi być zmienną lub wartością typu klasy, struktury lub interfejsu, który ma co najmniej jeden element członkowski indeksatora, w tym przypadku element_access jest dostępem indeksatora (dostęp do indeksatora).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).

Dostęp do tablicyArray access

W przypadku dostępu do tablicy primary_no_array_creation_expression element_access musi być wartością array_type.For an array access, the primary_no_array_creation_expression of the element_access must be a value of an array_type. Ponadto argument_list dostępu do tablicy nie może zawierać nazwanych argumentów. Liczba wyrażeń w argument_list musi być taka sama jak ranga array_type, a każde wyrażenie musi być typu int, uint, long, ulonglub musi być niejawnie konwertowane na jeden lub więcej z tych typów.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.

Wynikiem oceny dostępu do tablicy jest zmienna typu elementu tablicy, a mianowicie element tablicy wybrany przez wartości w wyrażeniach w argument_listach...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.

Przetwarzanie dostępu do tablicy w czasie wykonywania P[A], gdzie P jest primary_no_array_creation_expression array_type , a A to argument_list, składa się z następujących kroków: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 jest oceniane.P is evaluated. Jeśli ta Ocena spowoduje wyjątek, nie są wykonywane żadne dalsze kroki.If this evaluation causes an exception, no further steps are executed.
  • Wyrażenia indeksu argument_list są oceniane w kolejności, od lewej do prawej.The index expressions of the argument_list are evaluated in order, from left to right. Po dokonaniu oceny każdego wyrażenia indeksu niejawna konwersja (niejawne konwersje) do jednego z następujących typów jest wykonywana: 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. Pierwszy typ na tej liście, dla którego istnieje niejawna konwersja, jest wybierany.The first type in this list for which an implicit conversion exists is chosen. Na przykład jeśli wyrażenie index jest typu short, to niejawna konwersja na int jest wykonywana, ponieważ możliwe jest niejawne konwersje z short do int i z 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. Jeśli Obliczanie wyrażenia indeksu lub kolejnej niejawnej konwersji powoduje wyjątek, nie są oceniane żadne dalsze wyrażenia indeksu i nie są wykonywane żadne dalsze kroki.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.
  • Wartość P jest sprawdzana jako prawidłowa.The value of P is checked to be valid. Jeśli wartość P jest null, zostanie zgłoszony System.NullReferenceException i nie zostaną wykonane żadne dalsze kroki.If the value of P is null, a System.NullReferenceException is thrown and no further steps are executed.
  • Wartość każdego wyrażenia w argument_list jest sprawdzana względem rzeczywistych granic każdego wymiaru wystąpienia tablicy, do którego odwołuje się 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. Jeśli co najmniej jedna wartość znajduje się poza zakresem, zgłaszany jest System.IndexOutOfRangeException i nie są wykonywane żadne dalsze kroki.If one or more values are out of range, a System.IndexOutOfRangeException is thrown and no further steps are executed.
  • Obliczono lokalizację elementu tablicy podaną przez wyrażenia indeksu, a ta lokalizacja jest wynikiem dostępu do tablicy.The location of the array element given by the index expression(s) is computed, and this location becomes the result of the array access.

Dostęp indeksatoraIndexer access

W przypadku dostępu indeksatora primary_no_array_creation_expression element_access musi być zmienną lub wartością typu klasy, struktury lub interfejsu, a ten typ musi implementować jeden lub więcej indeksatorów, które są stosowane w odniesieniu do 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.

Przetwarzanie w czasie wiązania dostępu indeksatora P[A], gdzie P jest primary_no_array_creation_expressionem klasy, struktury lub typu interfejsu T, a A to argument_list, składa się z następujących kroków: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:

  • Zestaw indeksatorów udostępnianych przez T jest skonstruowany.The set of indexers provided by T is constructed. Zestaw składa się z wszystkich indeksatorów zadeklarowanych w T lub typu podstawowego T, które nie są override deklaracji i są dostępne w bieżącym kontekście (dostęp do elementu członkowskiego).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).
  • Zestaw jest zredukowany do tych indeksatorów, które mają zastosowanie i nie są ukryte przez inne indeksatory.The set is reduced to those indexers that are applicable and not hidden by other indexers. Poniższe reguły są stosowane do każdego indeksatora S.I w zestawie, gdzie S jest typem, w którym zadeklarowano I indeksatora: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:
  • Jeśli zestaw wyników indeksatorów jest pusty, nie ma żadnych odpowiednich indeksatorów i wystąpi błąd w czasie powiązania.If the resulting set of candidate indexers is empty, then no applicable indexers exist, and a binding-time error occurs.
  • Najlepszy indeksator zestawu indeksatorów kandydujących jest identyfikowany przy użyciu reguł rozpoznawania przeciążenia.The best indexer of the set of candidate indexers is identified using the overload resolution rules of Overload resolution. Jeśli nie można zidentyfikować pojedynczego najlepszego indeksatora, dostęp indeksatora jest niejednoznaczny i wystąpi błąd w czasie powiązania.If a single best indexer cannot be identified, the indexer access is ambiguous, and a binding-time error occurs.
  • Wyrażenia indeksu argument_list są oceniane w kolejności, od lewej do prawej.The index expressions of the argument_list are evaluated in order, from left to right. Wynikiem przetwarzania dostępu indeksatora jest wyrażenie sklasyfikowane jako dostęp indeksatora.The result of processing the indexer access is an expression classified as an indexer access. Wyrażenie dostępu indeksatora odwołuje się do indeksatora określonego w powyższym kroku i ma skojarzone wyrażenie wystąpienia P i skojarzoną listę argumentów 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.

W zależności od kontekstu, w którym jest używany, dostęp indeksatora powoduje wywołanie metody dostępu get lub set metody dostępu indeksatora.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. Jeśli dostęp indeksatora jest elementem docelowym przypisania, metoda dostępu set jest wywoływana, aby przypisać nową wartość (przypisanie proste).If the indexer access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). We wszystkich innych przypadkach metoda dostępu get jest wywoływana w celu uzyskania bieżącej wartości (wartości wyrażeń).In all other cases, the get accessor is invoked to obtain the current value (Values of expressions).

Ten dostępThis access

This_access składa się z zastrzeżonego słowa this.A this_access consists of the reserved word this.

this_access
    : 'this'
    ;

This_access jest dozwolony tylko w bloku konstruktora wystąpienia, metody wystąpienia lub akcesora wystąpienia.A this_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Ma jedną z następujących znaczenia:It has one of the following meanings:

  • Gdy this jest używana w primary_expression w konstruktorze wystąpienia klasy, zostanie sklasyfikowana jako wartość.When this is used in a primary_expression within an instance constructor of a class, it is classified as a value. Typ wartości to typ wystąpienia (Typ wystąpienia) klasy, w której występuje użycie, a wartość to odwołanie do konstruowanego obiektu.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.
  • Gdy this jest używana w primary_expression w metodzie wystąpienia lub metodach dostępu do wystąpienia klasy, jest klasyfikowana jako wartość.When this is used in a primary_expression within an instance method or instance accessor of a class, it is classified as a value. Typ wartości to typ wystąpienia (Typ wystąpienia) klasy, w której występuje użycie, a wartość to odwołanie do obiektu, dla którego wywołana została metoda lub akcesor.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.
  • Gdy this jest używany w primary_expression w konstruktorze wystąpienia struktury, jest on klasyfikowany jako zmienna.When this is used in a primary_expression within an instance constructor of a struct, it is classified as a variable. Typ zmiennej to typ wystąpienia (Typ wystąpienia) struktury, w której występuje użycie, a zmienna reprezentuje strukturę konstruowaną.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. Zmienna this konstruktora wystąpienia struktury zachowuje się dokładnie tak samo jak parametr out typu struct — w szczególności oznacza to, że zmienna musi być ostatecznie przypisana w każdej ścieżce wykonywania konstruktora wystąpień.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.
  • Gdy this jest używana w primary_expression w metodzie wystąpienia lub metodach dostępu do wystąpienia struktury, jest klasyfikowana jako zmienna.When this is used in a primary_expression within an instance method or instance accessor of a struct, it is classified as a variable. Typ zmiennej to typ wystąpienia (Typ wystąpienia) struktury, w której występuje użycie.The type of the variable is the instance type (The instance type) of the struct within which the usage occurs.
    • Jeśli metoda lub akcesor nie jest iteratorem (iteratorów), zmienna this reprezentuje strukturę, dla której wywołano metodę lub akcesor, i zachowuje się dokładnie tak samo jak parametr ref typu struktury.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.
    • Jeśli metoda lub akcesor jest iteratorem, zmienna this reprezentuje kopię struktury, dla której wywołano metodę lub akcesor, i zachowuje się dokładnie tak samo jak parametr wartości typu struktury.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.

Użycie this w primary_expression w kontekście innym niż wymienione powyżej jest błędem czasu kompilacji.Use of this in a primary_expression in a context other than the ones listed above is a compile-time error. W szczególności nie jest możliwe odwoływanie się do this w metodzie statycznej, metodzie dostępu do właściwości statycznych lub w variable_initializer deklaracji pola.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.

Dostęp podstawowyBase access

Base_access składa się z zastrzeżonego słowa base po którym następuje token "." i identyfikator lub argument_list ujęte w nawiasy kwadratowe: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 służy do uzyskiwania dostępu do składowych klasy bazowej, które są ukryte przez podobne nazwy członków w bieżącej klasie lub strukturze.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 jest dozwolony tylko w bloku konstruktora wystąpienia, metody wystąpienia lub akcesora wystąpienia.A base_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Gdy base.I występuje w klasie lub strukturze, I musi zwrócić element członkowski klasy podstawowej tej klasy lub struktury.When base.I occurs in a class or struct, I must denote a member of the base class of that class or struct. Podobnie, gdy base[E] występuje w klasie, odpowiedni indeksator musi istnieć w klasie bazowej.Likewise, when base[E] occurs in a class, an applicable indexer must exist in the base class.

W czasie trwania powiązania base_access wyrażenia base.I formularzy i base[E] są oceniane dokładnie tak, jakby były zapisywane ((B)this).I i ((B)this)[E], gdzie B jest klasą bazową klasy lub struktury, w której występuje konstrukcja.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. W ten sposób base.I i base[E] odpowiada this.I i this[E], z wyjątkiem tego, że this jest wyświetlany jako wystąpienie klasy bazowej.Thus, base.I and base[E] correspond to this.I and this[E], except this is viewed as an instance of the base class.

Gdy base_access odwołuje się do elementu członkowskiego funkcji wirtualnej (metody, właściwości lub indeksatora), określenie, który element członkowski funkcji ma zostać wywołany w czasie wykonywania (Sprawdzanie w czasie kompilacji dynamicznego rozpoznawania przeciążenia) jest zmieniany.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. Wywoływany element członkowski funkcji jest określany przez znalezienie najbardziej pochodnej implementacji (metod wirtualnych) elementu członkowskiego funkcji w odniesieniu do B (zamiast w odniesieniu do typu czasu wykonywania this, tak jak zwykle w przypadku dostępu niebazowego).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). W tym celu w override elementu członkowskiego funkcji virtual base_access może służyć do wywołania dziedziczonej implementacji elementu członkowskiego funkcji.Thus, within an override of a virtual function member, a base_access can be used to invoke the inherited implementation of the function member. Jeśli element członkowski funkcji, do którego odwołuje się base_access , jest abstrakcyjny, wystąpi błąd w czasie powiązania.If the function member referenced by a base_access is abstract, a binding-time error occurs.

Operatory przyrostka i zmniejszeniePostfix increment and decrement operators

post_increment_expression
    : primary_expression '++'
    ;

post_decrement_expression
    : primary_expression '--'
    ;

Operand przyrostkowej operacji zwiększania lub zmniejszania musi być wyrażeniem sklasyfikowanym jako zmienna, dostęp do właściwości lub dostęp indeksatora.The operand of a postfix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. Wynik operacji jest wartością tego samego typu co argument operacji.The result of the operation is a value of the same type as the operand.

Jeśli primary_expression ma typ czasu kompilacji dynamic następnie operator jest powiązany dynamicznie (powiązanie dynamiczne), post_increment_expression lub post_decrement_expression ma typ czasu kompilacji dynamic i w czasie wykonywania są stosowane następujące reguły z typem czasu wykonywania 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.

Jeśli operand przyrostowej operacji zwiększania lub zmniejszania jest dostępną właściwością lub indeksatorem, właściwość lub indeksator musi mieć zarówno get, jak i 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. W przeciwnym razie wystąpi błąd w czasie powiązania.If this is not the case, a binding-time error occurs.

Metoda rozpoznawania przeciążenia operatora jednoargumentowego (Metodarozpoznawania przeciążenia operatora jednoargumentowego) została zastosowana w celu wybrania implementacji określonego operatora.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Wstępnie zdefiniowane operatory ++ i -- istnieją dla następujących typów: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimali dowolnego typu wyliczeniowego.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Wstępnie zdefiniowane operatory ++ zwracają wartość wygenerowaną przez dodanie 1 do operandu, a wstępnie zdefiniowane operatory -- zwracają wartość wygenerowaną przez odjęcie 1 od operandu.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. W kontekście checked, jeśli wynik tego dodania lub odejmowania znajduje się poza zakresem typu wyników, a typ wyniku jest typem całkowitym lub typem wyliczeniowym, generowany jest 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.

Przetwarzanie w czasie wykonywania przyrostkowej przyrostowej lub zmniejszania operacji w postaci x++ lub x-- składa się z następujących kroków:The run-time processing of a postfix increment or decrement operation of the form x++ or x-- consists of the following steps:

  • Jeśli x jest sklasyfikowana jako zmienna:If x is classified as a variable:
    • x jest oceniane, aby utworzyć zmienną.x is evaluated to produce the variable.
    • Wartość x jest zapisywana.The value of x is saved.
    • Wybrany operator jest wywoływany z zapisaną wartością x jako argument.The selected operator is invoked with the saved value of x as its argument.
    • Wartość zwrócona przez operator jest przechowywana w lokalizacji podawanej przez ocenę x.The value returned by the operator is stored in the location given by the evaluation of x.
    • Zapisana wartość x jest wynikiem operacji.The saved value of x becomes the result of the operation.
  • Jeśli x jest klasyfikowany jako dostęp do właściwości lub indeksatora:If x is classified as a property or indexer access:
    • Wyrażenie wystąpienia (jeśli x nie jest static) i lista argumentów (jeśli x jest dostępem indeksatora), które są skojarzone z x są oceniane, a wyniki są używane w kolejnych getach i set metodach dostępu.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.
    • Metoda dostępu get x jest wywoływana, a zwrócona wartość jest zapisywana.The get accessor of x is invoked and the returned value is saved.
    • Wybrany operator jest wywoływany z zapisaną wartością x jako argument.The selected operator is invoked with the saved value of x as its argument.
    • Metoda dostępu set x jest wywoływana z wartością zwracaną przez operator jako argument value.The set accessor of x is invoked with the value returned by the operator as its value argument.
    • Zapisana wartość x jest wynikiem operacji.The saved value of x becomes the result of the operation.

Operatory ++ i -- obsługują również notację prefiksu (Operatory przyrostu i zmniejszania prefiksu).The ++ and -- operators also support prefix notation (Prefix increment and decrement operators). Zwykle wynik x++ lub x-- jest wartością x przed operacją, natomiast wynik ++x lub --x jest wartością x po operacji.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. W obu przypadkach x sama ma taką samą wartość po operacji.In either case, x itself has the same value after the operation.

Implementację operator ++ lub operator -- można wywołać przy użyciu notacji przyrostkowej lub prefiksowej.An operator ++ or operator -- implementation can be invoked using either postfix or prefix notation. Nie można mieć odrębnych implementacji operatora dla dwóch notacji.It is not possible to have separate operator implementations for the two notations.

Operator newThe new operator

Operator new jest używany do tworzenia nowych wystąpień typów.The new operator is used to create new instances of types.

Istnieją trzy formy new wyrażeń:There are three forms of new expressions:

  • Wyrażenia tworzenia obiektów są używane do tworzenia nowych wystąpień typów klas i typów wartości.Object creation expressions are used to create new instances of class types and value types.
  • Wyrażenia tworzenia tablic są używane do tworzenia nowych wystąpień typów tablicowych.Array creation expressions are used to create new instances of array types.
  • Wyrażenia tworzenia delegatów są używane do tworzenia nowych wystąpień typów delegatów.Delegate creation expressions are used to create new instances of delegate types.

Operator new sugeruje utworzenie wystąpienia typu, ale niekoniecznie ma dynamiczną alokację pamięci.The new operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. W szczególności wystąpienia typów wartości nie wymagają dodatkowej pamięci poza zmiennymi, w których się znajdują, i nie występują dynamiczne alokacje, gdy new jest używany do tworzenia wystąpień typów wartości.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.

Wyrażenia tworzenia obiektówObject creation expressions

Object_creation_expression jest używany do tworzenia nowego wystąpienia class_type lub 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
    ;

Typ object_creation_expression musi być class_type, value_type lub type_parameter.The type of an object_creation_expression must be a class_type, a value_type or a type_parameter. Typ nie może być abstract class_type.The type cannot be an abstract class_type.

Opcjonalne argument_list (listy argumentów) są dozwolone tylko wtedy, gdy Typ jest class_type lub struct_type.The optional argument_list (Argument lists) is permitted only if the type is a class_type or a struct_type.

Wyrażenie tworzenia obiektu może pominąć listę argumentów konstruktora i otaczające nawiasy, pod warunkiem że zawiera Inicjator obiektu lub inicjator kolekcji.An object creation expression can omit the constructor argument list and enclosing parentheses provided it includes an object initializer or collection initializer. Pominięcie listy argumentów konstruktora i otaczające nawiasy są równoważne do określenia pustej listy argumentów.Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.

Przetwarzanie wyrażenia tworzenia obiektu, które obejmuje inicjatora obiektów lub inicjator kolekcji, składa się z pierwszego przetwarzania konstruktora wystąpienia, a następnie przetwarzania inicjowania elementu członkowskiego lub elementu określonego przez inicjator obiektów (inicjatoryobiektów) lub inicjator kolekcji (inicjatorykolekcji).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).

Jeśli którykolwiek z argumentów w opcjonalnym argument_list ma typ czasu kompilowania dynamic, object_creation_expression jest powiązana dynamicznie (powiązanie dynamiczne), a w czasie wykonywania są stosowane następujące reguły przy użyciu typu czasu wykonywania tych argumentów argument_list z typem czasu kompilacji 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. Jednak tworzenie obiektów jest ograniczone przez ograniczony czas kompilacji, zgodnie z opisem w sprawdzaniu poprawności dynamicznego rozpoznawania przeciążenia.However, the object creation undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.

Przetwarzanie powiązania object_creation_expression formularza new T(A), gdzie T jest class_type lub value_type , a A jest opcjonalne argument_list, składa się z następujących kroków: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:

  • Jeśli T jest value_type i A nie istnieje:If T is a value_type and A is not present:
    • Object_creation_expression jest domyślnym wywołaniem konstruktora.The object_creation_expression is a default constructor invocation. Wynik object_creation_expression jest wartością typu T, a mianowicie wartością domyślną dla T zgodnie z definicją w typie 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.
  • W przeciwnym razie, jeśli T jest type_parameter i A nie istnieje:Otherwise, if T is a type_parameter and A is not present:
    • Jeśli dla Tnie określono ograniczenia typu wartości lub ograniczenia konstruktora (ograniczenia parametru typu), wystąpi błąd w czasie trwania powiązania.If no value type constraint or constructor constraint (Type parameter constraints) has been specified for T, a binding-time error occurs.
    • Wynik object_creation_expression jest wartością typu czasu wykonywania, z którym jest powiązany parametr typu, a mianowicie wynik wywołania domyślnego konstruktora tego typu.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. Typ czasu wykonywania może być typem referencyjnym lub typem wartości.The run-time type may be a reference type or a value type.
  • W przeciwnym razie, jeśli T jest class_type lub struct_type:Otherwise, if T is a class_type or a struct_type:
    • Jeśli T jest class_typeabstract, wystąpi błąd w czasie kompilacji.If T is an abstract class_type, a compile-time error occurs.
    • Konstruktor wystąpienia do wywołania jest określany przy użyciu reguł rozdzielczości przeciążenia przeciążania przeciążenia.The instance constructor to invoke is determined using the overload resolution rules of Overload resolution. Zestaw konstruktorów wystąpień kandydatów składa się z wszystkich dostępnych konstruktorów wystąpień zadeklarowanych w T, które mają zastosowanie w odniesieniu do A (odpowiedni element członkowski funkcji).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). Jeśli zestaw konstruktorów wystąpień kandydatów jest pusty lub nie można zidentyfikować pojedynczego konstruktora najlepszego wystąpienia, wystąpi błąd w czasie powiązania.If the set of candidate instance constructors is empty, or if a single best instance constructor cannot be identified, a binding-time error occurs.
    • Wynik object_creation_expression jest wartością typu T, a mianowicie wartość wygenerowaną przez wywołanie konstruktora wystąpienia określonego w powyższym kroku.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.
  • W przeciwnym razie object_creation_expression jest nieprawidłowy i wystąpi błąd w czasie powiązania.Otherwise, the object_creation_expression is invalid, and a binding-time error occurs.

Nawet jeśli object_creation_expression jest powiązana dynamicznie, typ czasu kompilacji nadal jest T.Even if the object_creation_expression is dynamically bound, the compile-time type is still T.

W czasie wykonywania object_creation_expression formularza new T(A), gdzie T jest class_type lub struct_type , a A jest opcjonalne argument_list, składa się z następujących kroków: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:

  • Jeśli T jest class_type:If T is a class_type:
    • Przydzielono nowe wystąpienie klasy T.A new instance of class T is allocated. Jeśli nie ma wystarczającej ilości pamięci do przydzielenia nowego wystąpienia, zostanie zgłoszony System.OutOfMemoryException i nie są wykonywane żadne dalsze kroki.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • Wszystkie pola nowego wystąpienia są inicjowane do ich wartości domyślnych (wartości domyślne).All fields of the new instance are initialized to their default values (Default values).
    • Konstruktor wystąpienia jest wywoływany zgodnie z regułami wywołania elementu członkowskiego funkcji (Sprawdzanie czasu kompilacji dynamicznego rozpoznawania przeciążenia).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Odwołanie do nowo przydzielonych wystąpień jest automatycznie przenoszone do konstruktora wystąpień i można uzyskać do niego dostęp z poziomu tego konstruktora jako 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.
  • Jeśli T jest struct_type:If T is a struct_type:
    • Wystąpienie typu T jest tworzone przez przydzielenie tymczasowej zmiennej lokalnej.An instance of type T is created by allocating a temporary local variable. Ponieważ Konstruktor wystąpienia struct_type jest wymagany do jednokrotnego przypisania wartości do każdego pola tworzonego wystąpienia, nie jest wymagane inicjowanie zmiennej tymczasowej.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.
    • Konstruktor wystąpienia jest wywoływany zgodnie z regułami wywołania elementu członkowskiego funkcji (Sprawdzanie czasu kompilacji dynamicznego rozpoznawania przeciążenia).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Odwołanie do nowo przydzielonych wystąpień jest automatycznie przenoszone do konstruktora wystąpień i można uzyskać do niego dostęp z poziomu tego konstruktora jako 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.

Inicjatory obiektówObject initializers

Inicjator obiektu określa wartości dla zero lub więcej pól, właściwości lub indeksowane elementy obiektu.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
    ;

Inicjator obiektu składa się z kolejności inicjatorów składowych, zawartych w tokenach { i } i rozdzielonych przecinkami.An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas. Każda member_initializer wyznacza element docelowy dla inicjalizacji.Each member_initializer designates a target for the initialization. Identyfikator musi mieć nazwę dostępnego pola lub właściwości obiektu, który jest inicjowany, podczas gdy argument_list ujęty w nawiasy kwadratowe muszą określać argumenty dostępnego indeksatora dla inicjowanego obiektu.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. Wystąpił błąd inicjatora obiektu, aby uwzględnić więcej niż jednego inicjatora elementu członkowskiego dla tego samego pola lub właściwości.It is an error for an object initializer to include more than one member initializer for the same field or property.

Każdy initializer_target następuje znak równości i wyrażenie, inicjator obiektu lub inicjator kolekcji.Each initializer_target is followed by an equals sign and either an expression, an object initializer or a collection initializer. Wyrażenia w inicjatorze obiektów nie są możliwe do odwoływania się do nowo utworzonego obiektu, który jest inicjowany.It is not possible for expressions within the object initializer to refer to the newly created object it is initializing.

Inicjator elementu członkowskiego, który określa wyrażenie po znaku równości jest przetwarzane w taki sam sposób jak przypisanie (przypisanie proste) do obiektu docelowego.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.

Inicjator elementu członkowskiego, który określa Inicjator obiektu po znaku równości, jest zagnieżdżonym inicjatorem obiektów, czyli inicjalizacją osadzonego obiektu.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. Zamiast przypisywać nową wartość do pola lub właściwości, przypisania w inicjatorze zagnieżdżonych obiektów są traktowane jako przypisania do elementów członkowskich pola lub właściwości.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. Inicjatory zagnieżdżonych obiektów nie mogą być stosowane do właściwości z typem wartości lub do pól tylko do odczytu z typem wartości.Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.

Inicjator elementu członkowskiego, który określa inicjator kolekcji po znaku równości jest inicjalizacją osadzonej kolekcji.A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Zamiast przypisywać nową kolekcję do pola docelowego, właściwości lub indeksatora elementy podane w inicjatorze są dodawane do kolekcji, do której odwołuje się element docelowy.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. Element docelowy musi być typu kolekcji, który spełnia wymagania określone w inicjatorach kolekcji.The target must be of a collection type that satisfies the requirements specified in Collection initializers.

Argumenty inicjatora indeksu zawsze będą oceniane dokładnie jeden raz.The arguments to an index initializer will always be evaluated exactly once. W związku z tym nawet jeśli argumenty zakończą się nigdy nie są używane (np. z powodu pustego inicjatora zagnieżdżonego), zostaną ocenione pod kątem ich efektów ubocznych.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.

Następująca Klasa reprezentuje punkt z dwoma współrzędnymi: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; } }
}

Wystąpienie Point można utworzyć i zainicjować w następujący sposób:An instance of Point can be created and initialized as follows:

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

ma ten sam skutek cowhich has the same effect as

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

gdzie __a jest niewidoczna w inny sposób i niedostępna zmienna tymczasowa.where __a is an otherwise invisible and inaccessible temporary variable. Następująca Klasa reprezentuje prostokąt utworzony na podstawie dwóch punktów: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; } }
}

Wystąpienie Rectangle można utworzyć i zainicjować w następujący sposób: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 }
};

ma ten sam skutek cowhich 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;

gdzie __r, __p1 i __p2 są zmiennymi tymczasowymi, które w przeciwnym razie są niewidoczne i niedostępne.where __r, __p1 and __p2 are temporary variables that are otherwise invisible and inaccessible.

Jeśli Konstruktor Rectangleprzydzieli dwa osadzone wystąpienia PointIf 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; } }
}

Następująca konstrukcja może służyć do inicjowania osadzonych wystąpień Point zamiast przypisywania nowych wystąpień: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 }
};

ma ten sam skutek cowhich 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;

Zgodnie z odpowiednią definicją C, Poniższy przykład: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] = {}
};

jest odpowiednikiem tej serii przypisań: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;

gdzie __citd., są generowane zmienne, które są niewidoczne i niedostępne dla kodu źródłowego.where __c, etc., are generated variables that are invisible and inaccessible to the source code. Należy zauważyć, że argumenty dla [0,0] są oceniane tylko raz, a argumenty dla [1,2] są oceniane raz, mimo że nigdy nie są używane.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.

Inicjatory kolekcjiCollection initializers

Inicjator kolekcji określa elementy kolekcji.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)*
    ;

Inicjator kolekcji składa się z sekwencji elementów inicjujących, ujętej w tokeny { i } i oddzielone przecinkami.A collection initializer consists of a sequence of element initializers, enclosed by { and } tokens and separated by commas. Każdy inicjator elementów określa element, który ma zostać dodany do inicjowanego obiektu kolekcji i składa się z listy wyrażeń ujętych w { i tokeny } i rozdzielonych przecinkami.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. Inicjator elementu pojedynczego wyrażenia może być zapisany bez nawiasów klamrowych, ale nie może być wyrażeniem przypisania, aby uniknąć niejednoznaczności z inicjatorami elementów członkowskich.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 produkcji jest zdefiniowany w wyrażeniu.The non_assignment_expression production is defined in Expression.

Poniżej znajduje się przykład wyrażenia tworzenia obiektu zawierającego inicjator kolekcji: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 };

Obiekt kolekcji, do którego zastosowano inicjator kolekcji, musi być typu, który implementuje System.Collections.IEnumerable lub wystąpi błąd w czasie kompilacji.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. Dla każdego określonego elementu w kolejności inicjator kolekcji wywołuje metodę Add w obiekcie docelowym z listą wyrażeń inicjatora elementu jako listą argumentów, stosując normalne wyszukiwanie elementów członkowskich i rozpoznawanie przeciążenia dla każdego wywołania.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. W ten sposób obiekt kolekcji musi mieć odpowiednie wystąpienie lub metodę rozszerzenia o nazwie Add dla każdego inicjatora elementu.Thus, the collection object must have an applicable instance or extension method with the name Add for each element initializer.

Następująca Klasa reprezentuje kontakt z nazwą i listą numerów telefonów: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> można utworzyć i zainicjować w następujący sposób: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" }
    }
};

ma ten sam skutek cowhich 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;

gdzie __clist, __c1 i __c2 są zmiennymi tymczasowymi, które w przeciwnym razie są niewidoczne i niedostępne.where __clist, __c1 and __c2 are temporary variables that are otherwise invisible and inaccessible.

Wyrażenia tworzenia tablicyArray creation expressions

Array_creation_expression służy do tworzenia nowego wystąpienia 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
    ;

Wyrażenie tworzenia tablicy w pierwszym formularzu przypisuje wystąpienie tablicy typu, które powoduje usunięcie każdego z poszczególnych wyrażeń z listy wyrażeń.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. Na przykład wyrażenie tworzenia tablicy new int[10,20] tworzy wystąpienie tablicy typu int[,], a wyrażenie tworzenia tablicy new int[10][,] tworzy tablicę typu 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[][,]. Każde wyrażenie na liście wyrażeń musi być typu int, uint, longlub ulonglub niejawnie konwertowane na jeden lub więcej z tych typów.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. Wartość każdego wyrażenia określa długość odpowiedniego wymiaru w nowo przydzielonym wystąpieniu tablicy.The value of each expression determines the length of the corresponding dimension in the newly allocated array instance. Ponieważ długość wymiaru tablicy nie może być ujemna, jest to błąd czasu kompilacji, który ma constant_expression z ujemną wartością na liście wyrażeń.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.

W przypadku niebezpiecznego kontekstu (niebezpieczne konteksty) nie określono układu tablic.Except in an unsafe context (Unsafe contexts), the layout of arrays is unspecified.

Jeśli wyrażenie tworzenia tablicowe w pierwszym formularzu zawiera inicjatora tablicy, każde wyrażenie na liście wyrażeń musi być stałą, a długość rangi i wymiary określona przez listę wyrażeń musi być zgodna z właściwościami inicjatora tablicy.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.

W wyrażeniu tworzenia tablicy drugiego lub trzeciego formularza ranga określonego typu tablicy lub specyfikatora rangi musi być zgodna z inicjatorem tablicy.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. Długości poszczególnych wymiarów są wywnioskowane na podstawie liczby elementów w każdym z odpowiednich poziomów zagnieżdżenia inicjatora tablicy.The individual dimension lengths are inferred from the number of elements in each of the corresponding nesting levels of the array initializer. W tym celu wyrażenieThus, the expression

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

dokładnie odpowiadaexactly corresponds to

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

Wyrażenie tworzenia tablicy trzeciego formularza jest określane jako wyrażenie tworzenia tablicy niejawnie wpisanej.An array creation expression of the third form is referred to as an implicitly typed array creation expression. Jest on podobny do drugiego formularza, z tą różnicą, że typ elementu tablicy nie jest jawnie określony, ale określony jako najlepszy typowy typ (znalezienie najlepszego wspólnego typu zestawu wyrażeń) zestawu wyrażeń w inicjatorze tablicy.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. Dla tablicy wielowymiarowej, tj., w której rank_specifier zawiera co najmniej jeden przecinek, ten zestaw składa się ze wszystkich wyrażeń, które znajdują się w zagnieżdżonych 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.

Inicjatory tablicy są szczegółowo opisane w inicjatorach tablicy.Array initializers are described further in Array initializers.

Wynik obliczania wyrażenia tworzenia tablicy jest klasyfikowany jako wartość, a mianowicie odwołanie do nowo przydzielonych wystąpień tablicy.The result of evaluating an array creation expression is classified as a value, namely a reference to the newly allocated array instance. Przetwarzanie wyrażenia tworzenia tablicy w czasie wykonywania składa się z następujących kroków:The run-time processing of an array creation expression consists of the following steps:

  • Wyrażenia długości wymiarów expression_list są oceniane w kolejności od lewej do prawej.The dimension length expressions of the expression_list are evaluated in order, from left to right. Po dokonaniu oceny każdego wyrażenia niejawna konwersja (niejawne konwersje) do jednego z następujących typów jest wykonywana: 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. Pierwszy typ na tej liście, dla którego istnieje niejawna konwersja, jest wybierany.The first type in this list for which an implicit conversion exists is chosen. Jeśli Obliczanie wyrażenia lub kolejnej niejawnej konwersji powoduje wyjątek, nie są oceniane żadne dalsze wyrażenia i nie są wykonywane żadne dalsze kroki.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.
  • Obliczone wartości dla długości wymiarów są weryfikowane w następujący sposób.The computed values for the dimension lengths are validated as follows. Jeśli co najmniej jedna z wartości jest mniejsza od zera, zostanie zgłoszony System.OverflowException i nie są wykonywane żadne dalsze kroki.If one or more of the values are less than zero, a System.OverflowException is thrown and no further steps are executed.
  • Przydzielono wystąpienie tablicy z podaną długością wymiaru.An array instance with the given dimension lengths is allocated. Jeśli nie ma wystarczającej ilości pamięci do przydzielenia nowego wystąpienia, zostanie zgłoszony System.OutOfMemoryException i nie są wykonywane żadne dalsze kroki.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
  • Wszystkie elementy nowego wystąpienia tablicy są inicjowane do ich wartości domyślnych (wartości domyślne).All elements of the new array instance are initialized to their default values (Default values).
  • Jeśli wyrażenie tworzenia tablicy zawiera inicjatora tablicy, każde wyrażenie w inicjatorze tablicy jest oceniane i przypisywane do odpowiadającego mu elementu tablicy.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. Obliczenia i przypisania są wykonywane w kolejności, w której wyrażenia są zapisywane w inicjatorze tablicy — innymi słowy, elementy są inicjowane w kolejności rosnącego indeksu, a najwyższego rzędu.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. Jeśli Obliczanie danego wyrażenia lub kolejnego przypisania do odpowiadającego elementu tablicy powoduje wyjątek, nie są inicjowane żadne dalsze elementy (a pozostałe elementy będą mieć wartości domyślne).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).

Wyrażenie tworzenia tablicy umożliwia utworzenie wystąpienia tablicy z elementami typu tablicy, ale elementy takich tablic muszą być inicjowane ręcznie.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. Na przykład, instrukcjaFor example, the statement

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

Tworzy tablicę jednowymiarową z 100 elementami typu int[].creates a single-dimensional array with 100 elements of type int[]. Wartość początkowa każdego elementu jest null.The initial value of each element is null. Nie jest możliwe dla tego samego wyrażenia tworzenia tablicy, które również tworzy wystąpienia tablic podrzędnych, i instrukcjiIt 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

powoduje błąd czasu kompilacji.results in a compile-time error. Zamiast tego należy wykonać ręczne tworzenie wystąpienia tablic podrzędnych, jak wInstantiation 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];

Gdy tablica tablic ma kształt "prostokątny", jeśli podtablice mają taką samą długość, bardziej wydajne jest użycie tablicy wielowymiarowej.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. W powyższym przykładzie Tworzenie wystąpienia tablicy tablic tworzy 101 obiektów — jedną tablicę zewnętrzną i tablicę podrzędną 100.In the example above, instantiation of the array of arrays creates 101 objects—one outer array and 100 sub-arrays. W przeciwieństwie doIn contrast,

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

tworzy tylko jeden obiekt, dwuwymiarową tablicę i wykonuje alokację w pojedynczej instrukcji.creates only a single object, a two-dimensional array, and accomplishes the allocation in a single statement.

Poniżej przedstawiono przykłady niejawnie wpisanych wyrażeń tworzenia tablicy: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

Ostatnie wyrażenie powoduje błąd czasu kompilacji, ponieważ żadne int ani string nie są niejawnie konwertowane na inne, więc nie ma żadnego najlepszego wspólnego typu.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. W tym przypadku należy użyć jawnie określonego wyrażenia tworzenia tablicy, na przykład określając typ, który ma być object[].An explicitly typed array creation expression must be used in this case, for example specifying the type to be object[]. Alternatywnie, jeden z elementów może być rzutowany na wspólny typ podstawowy, który następnie stanie się wywnioskowanym typem elementu.Alternatively, one of the elements can be cast to a common base type, which would then become the inferred element type.

Niejawnie wpisane wyrażenia tworzenia tablicy można łączyć z inicjatorami anonimowych obiektów (wyrażeniami tworzenia obiektów anonimowych) w celu tworzenia anonimowo wpisanych struktur danych.Implicitly typed array creation expressions can be combined with anonymous object initializers (Anonymous object creation expressions) to create anonymously typed data structures. Na przykład: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" }
    }
};

Delegowanie wyrażeń tworzeniaDelegate creation expressions

Delegate_creation_expression służy do tworzenia nowego wystąpienia delegate_type.A delegate_creation_expression is used to create a new instance of a delegate_type.

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

Argumentem wyrażenia tworzenia delegata musi być grupa metod, funkcja anonimowa lub wartość typu czasu kompilacji dynamic lub 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. Jeśli argument jest grupą metod, identyfikuje metodę i, dla metody wystąpienia, obiekt, dla którego ma zostać utworzony delegat.If the argument is a method group, it identifies the method and, for an instance method, the object for which to create a delegate. Jeśli argument jest funkcją anonimową, bezpośrednio definiuje parametry i treść metody obiektu docelowego delegata.If the argument is an anonymous function it directly defines the parameters and method body of the delegate target. Jeśli argument jest wartością, określa wystąpienie delegata, dla którego ma zostać utworzona kopia.If the argument is a value it identifies a delegate instance of which to create a copy.

Jeśli wyrażenie ma typ czasu kompilacji dynamic, delegate_creation_expression jest dynamicznie powiązane (powiązanie dynamiczne), a Poniższe reguły są stosowane w czasie wykonywania przy użyciu typu w czasie wykonywania wyrażenia.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. W przeciwnym razie reguły są stosowane w czasie kompilacji.Otherwise the rules are applied at compile-time.

Przetwarzanie powiązania delegate_creation_expression formularza new D(E), gdzie D jest delegate_type i E jest wyrażeniem, składa się z następujących kroków: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:

  • Jeśli E jest grupą metod, wyrażenie tworzenia delegata jest przetwarzane w taki sam sposób jak konwersja grup metod (konwersje grup metod) z E do 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.
  • Jeśli E jest funkcją anonimową, wyrażenie tworzenia delegata jest przetwarzane w taki sam sposób jak w przypadku konwersji funkcji anonimowej (konwersje funkcji anonimowych) z E do 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.
  • Jeśli E jest wartością, E muszą być zgodne (deklaracje delegatów) z D, a wynik jest odwołaniem do nowo utworzonego delegata typu D, który odwołuje się do tej samej listy wywołań co 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. Jeśli E nie jest zgodny z D, wystąpi błąd w czasie kompilacji.If E is not compatible with D, a compile-time error occurs.

Przetwarzanie delegate_creation_expression formularza new D(E), gdzie D jest delegate_type i E jest wyrażeniem, składa się z następujących kroków: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:

  • Jeśli E jest grupą metod, wyrażenie tworzenia delegata jest oceniane jako konwersja grup metod (konwersje grupmetod) z E do 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.
  • Jeśli E jest funkcją anonimową, tworzenie delegatów jest oceniane jako anonimowa funkcja konwersji z E do D (konwersje funkcji anonimowych).If E is an anonymous function, the delegate creation is evaluated as an anonymous function conversion from E to D (Anonymous function conversions).
  • Jeśli E jest wartością delegate_type:If E is a value of a delegate_type:
    • E jest oceniane.E is evaluated. Jeśli ta Ocena spowoduje wyjątek, nie są wykonywane żadne dalsze kroki.If this evaluation causes an exception, no further steps are executed.
    • Jeśli wartość E jest null, zostanie zgłoszony System.NullReferenceException i nie zostaną wykonane żadne dalsze kroki.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • Zostanie przydzielono nowe wystąpienie typu delegata D.A new instance of the delegate type D is allocated. Jeśli nie ma wystarczającej ilości pamięci do przydzielenia nowego wystąpienia, zostanie zgłoszony System.OutOfMemoryException i nie są wykonywane żadne dalsze kroki.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • Nowe wystąpienie delegata jest inicjowane z tą samą listą wywołania co wystąpienie delegata określone przez E.The new delegate instance is initialized with the same invocation list as the delegate instance given by E.

Lista wywołań delegata jest określana podczas tworzenia wystąpienia delegata, a następnie pozostaje stała dla całego okresu istnienia delegata.The invocation list of a delegate is determined when the delegate is instantiated and then remains constant for the entire lifetime of the delegate. Innymi słowy, nie można zmienić docelowej możliwej jednostki delegata po jego utworzeniu.In other words, it is not possible to change the target callable entities of a delegate once it has been created. Gdy dwa Delegaty są połączone lub jeden z nich jest usuwany z innego (deklaracje delegatów), nowe wyniki delegata; zawartość żadnego z istniejących delegatów nie została zmieniona.When two delegates are combined or one is removed from another (Delegate declarations), a new delegate results; no existing delegate has its contents changed.

Nie można utworzyć delegata, który odwołuje się do właściwości, indeksatora, zdefiniowanego przez użytkownika operatora, konstruktora wystąpienia, destruktora lub konstruktora statycznego.It is not possible to create a delegate that refers to a property, indexer, user-defined operator, instance constructor, destructor, or static constructor.

Jak opisano powyżej, gdy delegat jest tworzony na podstawie grupy metod, formalna lista parametrów i zwracany typ delegata określają, które z przeciążonych metod wybrać.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. w przykładzieIn 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;
    }
}

pole A.f jest inicjowane z delegatem, który odwołuje się do drugiej metody Square, ponieważ ta metoda dokładnie pasuje do formalnej listy parametrów i zwracanego typu 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. Druga metoda Square nie jest obecna, wystąpił błąd w czasie kompilacji.Had the second Square method not been present, a compile-time error would have occurred.

Wyrażenia tworzenia obiektów anonimowychAnonymous object creation expressions

Anonymous_object_creation_expression jest używany do tworzenia obiektu typu anonimowego.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
    ;

Inicjator obiektu anonimowego deklaruje typ anonimowy i zwraca wystąpienie tego typu.An anonymous object initializer declares an anonymous type and returns an instance of that type. Typ anonimowy to typ klasy pustego, który dziedziczy bezpośrednio z object.An anonymous type is a nameless class type that inherits directly from object. Elementy członkowskie typu anonimowego są sekwencją właściwości tylko do odczytu wywnioskowanej z inicjatora obiektu anonimowego używanego do tworzenia wystąpienia typu.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. W przypadku inicjatora obiektów anonimowych formularzaSpecifically, an anonymous object initializer of the form

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

deklaruje anonimowy typ formularzadeclares 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() { ... }
}

gdzie każdy Tx jest typem odpowiedniego wyrażenia ex.where each Tx is the type of the corresponding expression ex. Wyrażenie użyte w member_declarator musi mieć typ.The expression used in a member_declarator must have a type. W ten sposób jest to błąd czasu kompilacji dla wyrażenia w member_declarator być wartością null lub funkcją anonimową.Thus, it is a compile-time error for an expression in a member_declarator to be null or an anonymous function. Jest to również błąd czasu kompilacji dla wyrażenia, aby można było mieć niebezpieczny typ.It is also a compile-time error for the expression to have an unsafe type.

Nazwy typu anonimowego i parametru do jego metody Equals są generowane automatycznie przez kompilator i nie można się do niego odwoływać w tekście programu.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.

W ramach tego samego programu dwa anonimowe Inicjatory obiektów, które określają sekwencję właściwości tych samych nazw i typów czasu kompilacji w tej samej kolejności, spowodują wystąpienie tego samego typu anonimowego.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.

w przykładzieIn the example

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

przypisanie w ostatnim wierszu jest dozwolone, ponieważ p1 i p2 są tego samego typu anonimowego.the assignment on the last line is permitted because p1 and p2 are of the same anonymous type.

Metody Equals i GetHashcode na typach anonimowych przesłaniają metody dziedziczone z objecti są zdefiniowane w warunkach Equals i GetHashcode właściwości, tak aby dwa wystąpienia tego samego typu anonimowego były równe, jeśli wszystkie ich właściwości są równe.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.

Element członkowski deklarator może być skrócony do prostej nazwy (wnioskowanie o typie), dostęp do składowej (Sprawdzanie czasu kompilacji dynamicznego rozpoznawania przeciążenia), dostęp podstawowy (dostęp podstawowy) lub dostęp do składowej o wartości null (wyrażenia warunkowe o wartości null jako inicjatory projekcji).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). Jest to nazywane inicjatorem projekcji i jest skrótem dla deklaracji i przypisywania do właściwości o tej samej nazwie.This is called a projection initializer and is shorthand for a declaration of and assignment to a property with the same name. W każdym przypadku element członkowski Deklaratory formularzySpecifically, member declarators of the forms

identifier
expr.identifier

są dokładnie równoważne następujących odpowiednio:are precisely equivalent to the following, respectively:

identifier = identifier
identifier = expr.identifier

W tym celu w inicjatorze projekcji Identyfikator wybiera zarówno wartość, jak i pole lub właściwość, do której zostanie przypisana wartość.Thus, in a projection initializer the identifier selects both the value and the field or property to which the value is assigned. Intuicyjnie, inicjator projekcji nie tylko wartości, ale również nazwę wartości.Intuitively, a projection initializer projects not just a value, but also the name of the value.

Operator typeofThe typeof operator

Operator typeof służy do uzyskiwania obiektu System.Type dla typu.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
    : ','
    ;

Pierwsza forma typeof_expression składa się ze słowa kluczowego typeof, po którym następuje Typujęty w nawiasy.The first form of typeof_expression consists of a typeof keyword followed by a parenthesized type. Wynikiem wyrażenia tego formularza jest obiekt System.Type dla wskazanego typu.The result of an expression of this form is the System.Type object for the indicated type. Istnieje tylko jeden obiekt System.Type dla danego typu.There is only one System.Type object for any given type. Oznacza to, że dla typu T, typeof(T) == typeof(T) ma zawsze wartość true.This means that for a type T, typeof(T) == typeof(T) is always true. Typ nie może być dynamic.The type cannot be dynamic.

Druga forma typeof_expression składa się ze słowa kluczowego typeof, po którym następuje unbound_type_namew nawiasach.The second form of typeof_expression consists of a typeof keyword followed by a parenthesized unbound_type_name. Unbound_type_name jest bardzo podobna do TYPE_NAME (nazwi typównazw), z tą różnicą, że unbound_type_name zawiera generic_dimension_specifiers, gdzie TYPE_NAME zawiera 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. Gdy argument operacji typeof_expression jest sekwencją tokenów, które spełniają gramatyke obu unbound_type_name i TYPE_NAME, mianowicie, gdy nie zawiera generic_dimension_specifier ani type_argument_list, sekwencja tokenów jest uznawana za 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. Znaczenie unbound_type_name jest określane w następujący sposób:The meaning of an unbound_type_name is determined as follows:

  • Przekonwertuj sekwencję tokenów na TYPE_NAME , zastępując każdy generic_dimension_specifier type_argument_list o tej samej liczbie przecinki i słowo kluczowe object jako każdy 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.
  • Oceń wynikowy TYPE_NAME, ignorując wszystkie ograniczenia dotyczące parametrów typu.Evaluate the resulting type_name, while ignoring all type parameter constraints.
  • Unbound_type_name jest rozpoznawany jako niezwiązany typ ogólny skojarzony z wynikiem skonstruowanego typu (powiązane i niepowiązane typy).The unbound_type_name resolves to the unbound generic type associated with the resulting constructed type (Bound and unbound types).

Wynik typeof_expression jest obiektem System.Type dla wynikowego niepowiązanego typu ogólnego.The result of the typeof_expression is the System.Type object for the resulting unbound generic type.

Trzecia postać typeof_expression składa się ze słowa kluczowego typeof, po którym następuje słowo kluczowe void ujęte w nawiasy.The third form of typeof_expression consists of a typeof keyword followed by a parenthesized void keyword. Wynikiem wyrażenia tego formularza jest obiekt System.Type, który reprezentuje nieobecność typu.The result of an expression of this form is the System.Type object that represents the absence of a type. Obiekt typu zwracany przez typeof(void) jest odrębny od obiektu typu zwracanego dla dowolnego typu.The type object returned by typeof(void) is distinct from the type object returned for any type. Ten obiekt typu specjalnego jest przydatny w bibliotekach klas, które umożliwiają odbicie w metodach w języku, gdzie te metody chcą mieć sposób reprezentowania zwracanego typu dowolnej metody, w tym metod void, z wystąpieniem 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.

Operatora typeof można używać w parametrze typu.The typeof operator can be used on a type parameter. Wynik jest obiektem System.Type dla typu czasu wykonywania, który został powiązany z parametrem typu.The result is the System.Type object for the run-time type that was bound to the type parameter. Operatora typeof można również używać dla typu złożonego lub niepowiązanego typu ogólnego (powiązane i niepowiązane typy).The typeof operator can also be used on a constructed type or an unbound generic type (Bound and unbound types). Obiekt System.Type dla niepowiązanego typu ogólnego nie jest taki sam jak obiekt System.Type typu wystąpienia.The System.Type object for an unbound generic type is not the same as the System.Type object of the instance type. Typ wystąpienia zawsze jest zamkniętym skonstruowanym typem w czasie wykonywania, dlatego jego obiekt System.Type zależy od argumentów typu run w użyciu, podczas gdy niezwiązany typ ogólny nie ma argumentów typu.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.

PrzykładThe 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();
    }
}

tworzy następujące dane wyjściowe: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]

Należy pamiętać, że int i System.Int32 są tego samego typu.Note that int and System.Int32 are the same type.

Należy również zauważyć, że wynik typeof(X<>) nie zależy od argumentu Type, ale wynikiem typeof(X<T>) jest.Also note that the result of typeof(X<>) does not depend on the type argument but the result of typeof(X<T>) does.

Sprawdzone i niesprawdzone operatoryThe checked and unchecked operators

Operatory checked i unchecked są używane do kontrolowania kontekstu sprawdzania przepełnienia dla operacji arytmetycznych typu całkowitego i konwersji.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 ')'
    ;

Operator checked oblicza ujęte wyrażenie w sprawdzonym kontekście, a operator unchecked oblicza wyrażenie zawarte w niesprawdzonym kontekście.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 lub unchecked_expression odpowiada dokładnie na parenthesized_expression (wyrażeń ujętych w nawiasy), z tą różnicą, że zawarte wyrażenie jest oceniane w danym kontekście sprawdzania przepełnienia.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.

Kontekst sprawdzania przepełnienia można również kontrolować za pomocą instrukcji checked i unchecked (instrukcje sprawdzone i niesprawdzone).The overflow checking context can also be controlled through the checked and unchecked statements (The checked and unchecked statements).

Kontekst sprawdzania przepełnienia ma wpływ na następujące operacje checked i unchecked operatory i instrukcje:The following operations are affected by the overflow checking context established by the checked and unchecked operators and statements:

Gdy jedna z powyższych operacji tworzy wynik, który jest zbyt duży do reprezentowania w typie docelowym, kontekst, w którym wykonywana jest operacja, kontroluje Wynikowe zachowanie: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:

  • W kontekście checked, jeśli operacja jest wyrażeniem stałym (wyrażenia stałe), wystąpi błąd w czasie kompilacji.In a checked context, if the operation is a constant expression (Constant expressions), a compile-time error occurs. W przeciwnym razie, gdy operacja zostanie wykonana w czasie wykonywania, zostanie zgłoszony System.OverflowException.Otherwise, when the operation is performed at run-time, a System.OverflowException is thrown.
  • W kontekście unchecked wynik jest obcinany przez odrzucenie wszystkich bitów o dużej kolejności, które nie mieszczą się w typie docelowym.In an unchecked context, the result is truncated by discarding any high-order bits that do not fit in the destination type.

Dla wyrażeń niestałych (wyrażeń, które są oceniane w czasie wykonywania), które nie są ujęte w żadnej checked lub unchecked operatory lub instrukcje, domyślny kontekst sprawdzania przepełnienia jest unchecked, chyba że zewnętrzne czynniki (takie jak przełączniki kompilatora i konfiguracja środowiska wykonawczego) są wywoływane w celu checked oceny.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.

W przypadku wyrażeń stałych (wyrażenia, które mogą być w pełni oceniane w czasie kompilacji), domyślny kontekst sprawdzania przepełnienia jest zawsze checked.For constant expressions (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked. Jeśli wyrażenie stałe nie jest jawnie umieszczane w kontekście unchecked, przepełnienia, które wystąpiły podczas oceny czasu kompilowania wyrażenia, zawsze powodują błędy w czasie kompilacji.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.

Nie ma to wpływ na treść funkcji anonimowej checked ani kontekstów unchecked, w których występuje funkcja anonimowa.The body of an anonymous function is not affected by checked or unchecked contexts in which the anonymous function occurs.

w przykładzieIn 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
    }
}

nie zgłoszono błędów czasu kompilacji, ponieważ żadne wyrażenia nie mogą być oceniane w czasie kompilacji.no compile-time errors are reported since neither of the expressions can be evaluated at compile-time. W czasie wykonywania Metoda F zgłasza System.OverflowException, a metoda G zwraca-727379968 (Dolna część 32 bitów wyniku spoza zakresu).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). Zachowanie metody H zależy od domyślnego kontekstu sprawdzania przepełnienia dla kompilacji, ale jest taka sama jak F lub taka sama jak 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.

w przykładzieIn 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
    }
}

przepełnienia występujące podczas oceny wyrażeń stałych w F i H powodują zgłoszenie błędów w czasie kompilacji, ponieważ wyrażenia są oceniane w kontekście 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. Przepełnienie ma również miejsce podczas oceniania wyrażenia stałego w G, ale ponieważ Ocena odbywa się w kontekście unchecked, przepełnienie nie zostanie zgłoszone.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.

Operatory checked i unchecked mają wpływ tylko na kontekst sprawdzania przepełnienia dla tych operacji, które są umieszczone w formie tekstowej w tokenach "(" i ")".The checked and unchecked operators only affect the overflow checking context for those operations that are textually contained within the "(" and ")" tokens. Operatory nie mają wpływu na składowe funkcji, które są wywoływane w wyniku obliczania zawartego wyrażenia.The operators have no effect on function members that are invoked as a result of evaluating the contained expression. w przykładzieIn the example

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

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

Użycie checked w F nie wpływa na ocenę x * y w Multiply, dlatego x * y jest oceniane w kontekście domyślnego sprawdzania przepełnienia.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.

Operator unchecked jest wygodny podczas pisania stałych z podpisanych typów całkowitych w notacji szesnastkowej.The unchecked operator is convenient when writing constants of the signed integral types in hexadecimal notation. Na przykład:For example:

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

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

Obie stałe szesnastkowe powyżej są typu uint.Both of the hexadecimal constants above are of type uint. Ze względu na to, że stałe są poza zakresem int, bez operatora unchecked, rzutowania do int spowodują błędy w czasie kompilacji.Because the constants are outside the int range, without the unchecked operator, the casts to int would produce compile-time errors.

Operatory checked i unchecked i instrukcje umożliwiają programistom kontrolowanie niektórych aspektów niektórych obliczeń liczbowych.The checked and unchecked operators and statements allow programmers to control certain aspects of some numeric calculations. Jednak zachowanie niektórych operatorów numerycznych zależy od typów danych argumentów operacji.However, the behavior of some numeric operators depends on their operands' data types. Na przykład mnożenie dwóch miejsc dziesiętnych zawsze powoduje wyjątek w przypadku przepełnienia nawet w jawnej konstrukcji unchecked.For example, multiplying two decimals always results in an exception on overflow even within an explicitly unchecked construct. Podobnie mnożenie dwóch wartości zmiennoprzecinkowych nigdy nie powoduje wyjątku w przypadku przepełnienia nawet w jawnej konstrukcji checked.Similarly, multiplying two floats never results in an exception on overflow even within an explicitly checked construct. Ponadto inne operatory nigdy nie mają wpływ na tryb sprawdzania, bez względu na to, czy jest to ustawienie domyślne, czy jawne.In addition, other operators are never affected by the mode of checking, whether default or explicit.

Wyrażenia wartości domyślnychDefault value expressions

Domyślne wyrażenie wartości służy do uzyskiwania wartości domyślnej (wartości domyślne) typu.A default value expression is used to obtain the default value (Default values) of a type. Zwykle wyrażenie wartości domyślnej jest używane dla parametrów typu, ponieważ może być nieznane, jeśli parametr typu jest typem wartości lub typem referencyjnym.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. (Nie istnieje konwersja z literału null do parametru typu, chyba że parametr typu jest znany jako typ referencyjny).(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 ')'
    ;

Jeśli Typ w default_value_expression jest obliczany w czasie wykonywania do typu referencyjnego, wynik jest null konwertowany na ten typ.If the type in a default_value_expression evaluates at run-time to a reference type, the result is null converted to that type. Jeśli Typ w default_value_expression jest obliczany w czasie wykonywania do typu wartości, wynik jest wartością domyślną value_type(konstruktory domyślne).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 jest wyrażeniem stałym (wyrażenia stałe), jeśli typ jest typem referencyjnym lub parametrem typu, który jest znany jako typ referencyjny (ograniczenia parametru typu).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). Ponadto default_value_expression jest wyrażeniem stałym, jeśli typ jest jednym z następujących typów wartości: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, boollub dowolnego typu wyliczenia.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.

Wyrażenia nameofNameof expressions

Nameof_expression służy do uzyskania nazwy jednostki programu jako ciągu stałej.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
    ;

Mówiąc gramatycznie, argument operacji named_entity jest zawsze wyrażeniem.Grammatically speaking, the named_entity operand is always an expression. Ponieważ nameof nie jest zastrzeżonym słowem kluczowym, wyrażenie NameOf jest zawsze niejednoznaczne syntaktycznie z wywołaniem prostej nazwy nameof.Because nameof is not a reserved keyword, a nameof expression is always syntactically ambiguous with an invocation of the simple name nameof. Ze względów zgodności, jeśli nazwa wyszukiwania nazw (proste nazwy) nameof się powiedzie, wyrażenie jest traktowane jako invocation_expression --niezależnie od tego, czy wywołanie jest prawne.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. W przeciwnym razie jest nameof_expression.Otherwise it is a nameof_expression.

Znaczenie named_entity nameof_expression jest jego znaczeniem jako wyrażenia; oznacza to, że jako simple_name, base_access lub 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. Jednak jeśli odnośnik opisany w temacie proste nazwy i dostęp do elementu członkowskiego powoduje błąd, ponieważ element członkowski wystąpienia został znaleziony w kontekście statycznym, nameof_expression nie tworzy takiego błędu.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.

Jest to błąd czasu kompilacji dla named_entity wyznaczania grupy metod w celu uzyskania type_argument_list.It is a compile-time error for a named_entity designating a method group to have a type_argument_list. Jest to błąd czasu kompilowania dla named_entity_target typu dynamic.It is a compile time error for a named_entity_target to have the type dynamic.

Nameof_expression jest wyrażeniem stałym typu stringi nie ma wpływu na środowisko uruchomieniowe.A nameof_expression is a constant expression of type string, and has no effect at runtime. Named_entity nie jest oceniana i jest ignorowany w celach analizy z określonym przydziałem (ogólne reguły dla prostych wyrażeń).Specifically, its named_entity is not evaluated, and is ignored for the purposes of definite assignment analysis (General rules for simple expressions). Jego wartość to ostatni identyfikator named_entity przed opcjonalnym type_argument_listkońcowym, przekształcony w następujący sposób:Its value is the last identifier of the named_entity before the optional final type_argument_list, transformed in the following way:

  • Prefiks "@", jeśli jest używany, jest usuwany.The prefix "@", if used, is removed.
  • Każda unicode_escape_sequence jest przekształcana do odpowiedniego znaku Unicode.Each unicode_escape_sequence is transformed into its corresponding Unicode character.
  • Wszystkie formatting_characters są usuwane.Any formatting_characters are removed.

Są to te same przekształcenia, które są stosowane w identyfikatorach podczas testowania równości między identyfikatorami.These are the same transformations applied in Identifiers when testing equality between identifiers.

Do zrobienia: przykładyTODO: examples

Wyrażenia metody anonimowejAnonymous method expressions

Anonymous_method_expression to jeden z dwóch sposobów definiowania funkcji anonimowej.An anonymous_method_expression is one of two ways of defining an anonymous function. Są one dokładniej opisane w wyrażeniach funkcji anonimowych.These are further described in Anonymous function expressions.

Operatory jednoargumentoweUnary operators

Operatory ?, +, -, !, ~, ++, --, Cast i await są nazywane operatorami jednoargumentowymi.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
    ;

Jeśli argument operacji unary_expression ma typ czasu kompilacji dynamic, jest on dynamicznie powiązany (powiązanie dynamiczne).If the operand of a unary_expression has the compile-time type dynamic, it is dynamically bound (Dynamic binding). W takim przypadku typ czasu kompilacji unary_expression jest dynamic, a rozwiązanie opisane poniżej zostanie wykonane w czasie wykonywania przy użyciu typu czasu wykonywania argumentu operacji.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.

Operator warunkowy o wartości nullNull-conditional operator

Operator warunkowy null stosuje listę operacji do operandu tylko wtedy, gdy ten operand ma wartość różną od null.The null-conditional operator applies a list of operations to its operand only if that operand is non-null. W przeciwnym razie wynik zastosowania operatora jest 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? ')'
    ;

Lista operacji może obejmować dostęp do składowych i operacje dostępu do elementów (które mogą być w stanie null — warunkowo), a także wywołania.The list of operations can include member access and element access operations (which may themselves be null-conditional), as well as invocation.

Na przykład wyrażenie a.b?[0]?.c() jest null_conditional_expression z primary_expression a.b i null_conditional_operations ?[0] (dostęp warunkowy o wartości null), ?.c (dostęp do elementu członkowskiego o wartości null) i () (wywołanie).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).

W przypadku null_conditional_expression E z primary_expression P, niech E0 być wyrażeniem, które zostało uzyskane przez usunięcie wiodącego ? z każdej 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. Koncepcyjnie, E0 jest wyrażeniem, które zostanie ocenione, jeśli żadne sprawdzenie wartości null nie zostało reprezentowane przez ?s nie null.Conceptually, E0 is the expression that will be evaluated if none of the null checks represented by the ?s do find a null.

Ponadto, niech E1 być wyrażeniem, które można usunąć przez usunięcie wiodącego ? z zaledwie pierwszego null_conditional_operations w E.Also, let E1 be the expression obtained by textually removing the leading ? from just the first of the null_conditional_operations in E. Może to prowadzić do wyrażenia podstawowego (jeśli istnieje tylko jeden ?) lub do innego null_conditional_expression.This may lead to a primary-expression (if there was just one ?) or to another null_conditional_expression.

Na przykład jeśli E jest wyrażeniem a.b?[0]?.c(), E0 jest wyrażeniem a.b[0].c() i E1 jest wyrażeniem 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().

Jeśli E0 jest sklasyfikowany jako Nothing, E zaklasyfikowane jako Nothing.If E0 is classified as nothing, then E is classified as nothing. W przeciwnym razie E jest klasyfikowane jako wartość.Otherwise E is classified as a value.

E0 i E1 są używane do określenia znaczenia E:E0 and E1 are used to determine the meaning of E:

  • Jeśli E występuje jako statement_expression znaczenie E jest takie samo jak instrukcjaIf E occurs as a statement_expression the meaning of E is the same as the statement

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

    z tą różnicą, że P jest oceniane tylko raz.except that P is evaluated only once.

  • W przeciwnym razie, jeśli E0 jest sklasyfikowany jako Brak błędu w czasie kompilacji.Otherwise, if E0 is classified as nothing a compile-time error occurs.

  • W przeciwnym razie niech T0 być typem E0.Otherwise, let T0 be the type of E0.

    • Jeśli T0 jest parametrem typu, który nie jest znany jako typ referencyjny lub typ wartości niedopuszczający wartości null, wystąpi błąd w czasie kompilacji.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.

    • Jeśli T0 ma typ wartości niedopuszczający wartości null, typ E jest T0?, a znaczenie E jest takie samo jakIf 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
      

      z tą różnicą, że P jest oceniane tylko raz.except that P is evaluated only once.

    • W przeciwnym razie typ E jest T0, a znaczenie E jest takie samo jakOtherwise the type of E is T0, and the meaning of E is the same as

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

      z tą różnicą, że P jest oceniane tylko raz.except that P is evaluated only once.

Jeśli E1 należy do null_conditional_expression, te reguły są stosowane ponownie, zagnieżdżając testy dla null do momentu braku dalszych ?, a wyrażenie zostało zredukowane w dół do E0wyrażenia podstawowego.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.

Na przykład, jeśli wyrażenie a.b?[0]?.c() występuje jako wyrażenie instrukcji, jak w instrukcji:For example, if the expression a.b?[0]?.c() occurs as a statement-expression, as in the statement:

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

jego znaczenie jest równoważne z:its meaning is equivalent to:

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

co ponownie jest równoważne:which again is equivalent to:

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

Z tą różnicą, że a.b i a.b[0] są oceniane tylko raz.Except that a.b and a.b[0] are evaluated only once.

Jeśli występuje w kontekście, w którym jego wartość jest używana, jak w:If it occurs in a context where its value is used, as in:

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

przy założeniu, że typ końcowego wywołania nie jest typem wartości niedopuszczających wartości null, jego znaczenie jest równoważne: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();

Z tą różnicą, że a.b i a.b[0] są oceniane tylko raz.except that a.b and a.b[0] are evaluated only once.

Wyrażenia warunkowe o wartości null jako inicjatory projekcjiNull-conditional expressions as projection initializers

Wyrażenie warunkowe o wartości null jest dozwolone tylko jako member_declarator w anonymous_object_creation_expression (wyrażenia anonimowego tworzenia obiektów), jeśli zostanie zakończone przez (opcjonalnie wartość null) członek.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. Gramatycznie ten wymóg może być wyrażony jako: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?
    ;

Jest to specjalny przypadek gramatyki dla null_conditional_expression powyżej.This is a special case of the grammar for null_conditional_expression above. Produkcja dla member_declarator w wyrażeniach tworzenia obiektów anonimowych , a następnie zawiera tylko null_conditional_member_access.The production for member_declarator in Anonymous object creation expressions then includes only null_conditional_member_access.

Wyrażenia warunkowe o wartości null jako wyrażenia instrukcjiNull-conditional expressions as statement expressions

Wyrażenie warunkowe o wartości null jest dozwolone tylko jako statement_expression (instrukcje wyrażenia), jeśli zostanie zakończone wywołaniem.A null-conditional expression is only allowed as a statement_expression (Expression statements) if it ends with an invocation. Gramatycznie ten wymóg może być wyrażony jako:Grammatically, this requirement can be expressed as:

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

Jest to specjalny przypadek gramatyki dla null_conditional_expression powyżej.This is a special case of the grammar for null_conditional_expression above. Środowisko produkcyjne dla statement_expression w instrukcjach wyrażeń zawiera tylko null_conditional_invocation_expression.The production for statement_expression in Expression statements then includes only null_conditional_invocation_expression.

Jednoargumentowy operator plusUnary plus operator

Aby można było wykonać operację +x, do wybrania implementacji określonego operatora jest stosowana metoda rozpoznawania przeciążenia operatorajednoargumentowego.For an operation of the form +x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Operand jest konwertowany na typ parametru wybranego operatora, a typ wyniku jest typem zwracanym operatora.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. Wstępnie zdefiniowane operatory jednoargumentowe Plus są następujące: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);

Dla każdego z tych operatorów wynik jest po prostu wartością operandu.For each of these operators, the result is simply the value of the operand.

Jednoargumentowy operator minusUnary minus operator

Aby można było wykonać operację -x, do wybrania implementacji określonego operatora jest stosowana metoda rozpoznawania przeciążenia operatorajednoargumentowego.For an operation of the form -x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Operand jest konwertowany na typ parametru wybranego operatora, a typ wyniku jest typem zwracanym operatora.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. Wstępnie zdefiniowane operatory negacji to:The predefined negation operators are:

  • Negacja liczby całkowitej:Integer negation:

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

    Wynik jest obliczany przez odjęcie x od zera.The result is computed by subtracting x from zero. Jeśli wartość x jest najmniejszą reprezentacją wartości typu operandu (-2 ^ 31 dla int lub-2 ^ 63 dla long), matematyczna Negacja x nie jest reprezentacja w typie operandu.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. W takim przypadku w kontekście checked zostanie zgłoszony System.OverflowException; Jeśli występuje w kontekście unchecked, wynik jest wartością operandu, a przepełnienie nie zostanie zgłoszone.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.

    Jeśli argument operacji operatora negacji jest typu uint, jest konwertowany na typ longi typ wyniku jest 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. Wyjątkiem jest reguła zezwalająca na zapisanie wartości int-2147483648 (-2 ^ 31) jako dziesiętnego literału liczb całkowitych (literałów liczb całkowitych).An exception is the rule that permits the int value -2147483648 (-2^31) to be written as a decimal integer literal (Integer literals).

    Jeśli argument operacji operatora negacji jest typu ulong, wystąpi błąd w czasie kompilacji.If the operand of the negation operator is of type ulong, a compile-time error occurs. Wyjątkiem jest reguła zezwalająca na zapisanie wartości long-zakresu od (-2 ^ 63) jako dziesiętnego literału liczb całkowitych (literałów liczb całkowitych).An exception is the rule that permits the long value -9223372036854775808 (-2^63) to be written as a decimal integer literal (Integer literals).

  • Negacja zmiennoprzecinkowa:Floating-point negation:

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

    Wynikiem jest wartość x z odwróconym znakiem.The result is the value of x with its sign inverted. Jeśli x jest NaN, wynik jest również NaN.If x is NaN, the result is also NaN.

  • Negacja dziesiętna:Decimal negation:

    decimal operator -(decimal x);
    

    Wynik jest obliczany przez odjęcie x od zera.The result is computed by subtracting x from zero. Negacja dziesiętna jest równoznaczna z użyciem jednoargumentowego operatora minus typu System.Decimal.Decimal negation is equivalent to using the unary minus operator of type System.Decimal.

Operator logiczny negacjiLogical negation operator

Aby można było wykonać operację !x, do wybrania implementacji określonego operatora jest stosowana metoda rozpoznawania przeciążenia operatorajednoargumentowego.For an operation of the form !x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Operand jest konwertowany na typ parametru wybranego operatora, a typ wyniku jest typem zwracanym operatora.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. Istnieje tylko jeden wstępnie zdefiniowany operator logiczny negacji:Only one predefined logical negation operator exists:

bool operator !(bool x);

Ten operator oblicza logiczne Negacja operandu: Jeśli operand jest true, wynik jest false.This operator computes the logical negation of the operand: If the operand is true, the result is false. Jeśli argument jest false, wynik jest true.If the operand is false, the result is true.

Operator dopełnienia bitowegoBitwise complement operator

Aby można było wykonać operację ~x, do wybrania implementacji określonego operatora jest stosowana metoda rozpoznawania przeciążenia operatorajednoargumentowego.For an operation of the form ~x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Operand jest konwertowany na typ parametru wybranego operatora, a typ wyniku jest typem zwracanym operatora.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. Wstępnie zdefiniowane operatory dopełnienia bitowego są następujące:The predefined bitwise complement operators are:

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

Dla każdego z tych operatorów wynik operacji jest bitowym uzupełnieniem x.For each of these operators, the result of the operation is the bitwise complement of x.

Każdy typ wyliczeniowy E niejawnie udostępnia następujący operator dopełnienia bitowego:Every enumeration type E implicitly provides the following bitwise complement operator:

E operator ~(E x);

Wynik oceny ~x, gdzie x jest wyrażeniem typu wyliczenia E z Utypu podstawowego, jest dokładnie taka sama jak Ocena (E)(~(U)x), z tą różnicą, że konwersja do E jest zawsze wykonywana tak jak w kontekście unchecked (Operatory sprawdzone i niezaznaczone).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).

Operatory prefiksów inkrementacji i dekrementacjiPrefix increment and decrement operators

pre_increment_expression
    : '++' unary_expression
    ;

pre_decrement_expression
    : '--' unary_expression
    ;

Operand operacji zwiększania lub zmniejszania prefiksu musi być wyrażeniem sklasyfikowanym jako zmienna, dostępem do właściwości lub dostępem indeksatora.The operand of a prefix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. Wynik operacji jest wartością tego samego typu co argument operacji.The result of the operation is a value of the same type as the operand.

Jeśli operand operacji przyrostu lub zmniejszania prefiksu jest właściwością lub indeksatorem, właściwość lub indeksator musi mieć zarówno get, jak i metodę dostępu 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. W przeciwnym razie wystąpi błąd w czasie powiązania.If this is not the case, a binding-time error occurs.

Metoda rozpoznawania przeciążenia operatora jednoargumentowego (Metodarozpoznawania przeciążenia operatora jednoargumentowego) została zastosowana w celu wybrania implementacji określonego operatora.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Wstępnie zdefiniowane operatory ++ i -- istnieją dla następujących typów: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimali dowolnego typu wyliczeniowego.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Wstępnie zdefiniowane operatory ++ zwracają wartość wygenerowaną przez dodanie 1 do operandu, a wstępnie zdefiniowane operatory -- zwracają wartość wygenerowaną przez odjęcie 1 od operandu.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. W kontekście checked, jeśli wynik tego dodania lub odejmowania znajduje się poza zakresem typu wyników, a typ wyniku jest typem całkowitym lub typem wyliczeniowym, generowany jest 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.

Przetwarzanie w czasie wykonywania operacji przyrostu lub zmniejszania prefiksu w formularzu ++x lub --x składa się z następujących kroków:The run-time processing of a prefix increment or decrement operation of the form ++x or --x consists of the following steps:

  • Jeśli x jest sklasyfikowana jako zmienna:If x is classified as a variable:
    • x jest oceniane, aby utworzyć zmienną.x is evaluated to produce the variable.
    • Wybrany operator jest wywoływany z wartością x jako argumentem.The selected operator is invoked with the value of x as its argument.
    • Wartość zwrócona przez operator jest przechowywana w lokalizacji podawanej przez ocenę x.The value returned by the operator is stored in the location given by the evaluation of x.
    • Wartość zwracana przez operatora jest wynikiem operacji.The value returned by the operator becomes the result of the operation.
  • Jeśli x jest klasyfikowany jako dostęp do właściwości lub indeksatora:If x is classified as a property or indexer access:
    • Wyrażenie wystąpienia (jeśli x nie jest static) i lista argumentów (jeśli x jest dostępem indeksatora), które są skojarzone z x są oceniane, a wyniki są używane w kolejnych getach i set metodach dostępu.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.
    • Metoda dostępu get x jest wywoływana.The get accessor of x is invoked.
    • Wybrany operator jest wywoływany z wartością zwracaną przez metodę dostępu get jako argument.The selected operator is invoked with the value returned by the get accessor as its argument.
    • Metoda dostępu set x jest wywoływana z wartością zwracaną przez operator jako argument value.The set accessor of x is invoked with the value returned by the operator as its value argument.
    • Wartość zwracana przez operatora jest wynikiem operacji.The value returned by the operator becomes the result of the operation.

Operatory ++ i -- obsługują również notację przyrostkową (przyrostowe i zmniejszające się operatory).The ++ and -- operators also support postfix notation (Postfix increment and decrement operators). Zwykle wynik x++ lub x-- jest wartością x przed operacją, natomiast wynik ++x lub --x jest wartością x po operacji.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. W obu przypadkach x sama ma taką samą wartość po operacji.In either case, x itself has the same value after the operation.

Implementację operator++ lub operator-- można wywołać przy użyciu notacji przyrostkowej lub prefiksowej.An operator++ or operator-- implementation can be invoked using either postfix or prefix notation. Nie można mieć odrębnych implementacji operatora dla dwóch notacji.It is not possible to have separate operator implementations for the two notations.

Wyrażenia rzutowaniaCast expressions

Cast_expression służy do jawnej konwersji wyrażenia na dany typ.A cast_expression is used to explicitly convert an expression to a given type.

cast_expression
    : '(' type ')' unary_expression
    ;

Cast_expression formularza (T)E, gdzie T jest typem , a E jest unary_expression, wykonuje jawną konwersję (jawne konwersje) wartości E do typu 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. Jeśli nie istnieje jawna konwersja z E na T, wystąpi błąd w czasie trwania powiązania.If no explicit conversion exists from E to T, a binding-time error occurs. W przeciwnym razie wynik jest wartością wygenerowaną przez konwersję jawną.Otherwise, the result is the value produced by the explicit conversion. Wynik jest zawsze klasyfikowany jako wartość, nawet jeśli E oznacza zmienną.The result is always classified as a value, even if E denotes a variable.

Gramatyka cast_expression prowadzi do pewnej składni niejasności.The grammar for a cast_expression leads to certain syntactic ambiguities. Na przykład wyrażenie (x)-y może być interpretowane jako cast_expression (rzutowanie -y do typu x) lub jako additive_expression połączone z parenthesized_expression (które oblicza wartość 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).

Aby rozwiązać cast_expression niejasności, istnieje następująca reguła: sekwencja jednego lub więcej tokenów(białych znaków) ujętych w nawiasy jest uważana za początek cast_expression tylko wtedy, gdy co najmniej jeden z następujących warunków jest spełniony: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:

  • Sekwencja tokenów jest poprawną gramatyką dla typu, ale nie dla wyrażenia.The sequence of tokens is correct grammar for a type, but not for an expression.
  • Sekwencja tokenów jest poprawną gramatyką dla typu, a token bezpośrednio po nawiasach zamykających jest tokenem "~", tokenem "!", tokenem "(", identyfikatorem (sekwencjami ucieczki znaków Unicode), literałem (literałów) lub słowem kluczowym (Keywords), z wyjątkiem as i 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.

Termin "poprawna Gramatyka" oznacza tylko, że sekwencja tokenów musi być zgodna z konkretną produkcją gramatyczną.The term "correct grammar" above means only that the sequence of tokens must conform to the particular grammatical production. W szczególności nie należy traktować faktycznego znaczenia identyfikatorów składników.It specifically does not consider the actual meaning of any constituent identifiers. Na przykład jeśli x i y są identyfikatorami, x.y jest poprawną gramatyką dla typu, nawet jeśli x.y nie wskazuje typu.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.

Z poziomu reguły uściślania, która następuje, jeśli x i y są identyfikatorami, (x)y, (x)(y)i (x)(-y)cast_expressions, ale (x)-y nie jest, nawet jeśli x identyfikuje typ.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. Jeśli jednak x jest słowem kluczowym, który identyfikuje wstępnie zdefiniowany typ (na przykład int), wówczas wszystkie cztery formy są cast_expressions (ponieważ takie słowo kluczowe nie może być wyrażeniem przez siebie).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).

Wyrażenia awaitAwait expressions

Operator await jest używany do zawieszania oceny otaczającej funkcji asynchronicznej do momentu zakończenia operacji asynchronicznej reprezentowanej przez operand.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 jest dozwolony tylko w treści funkcji asynchronicznej (Iteratory).An await_expression is only allowed in the body of an async function (Iterators). W najbliższych otaczającej funkcji asynchronicznej await_expression mogą nie wystąpić w tych miejscach:Within the nearest enclosing async function, an await_expression may not occur in these places:

  • Wewnątrz zagnieżdżonej funkcji anonimowej (innej niż Async)Inside a nested (non-async) anonymous function
  • Wewnątrz bloku lock_statementInside the block of a lock_statement
  • W niebezpiecznym kontekścieIn an unsafe context

Należy zauważyć, że await_expression nie może wystąpić w większości miejsc w query_expression, ponieważ są składniowo przekształcone w celu użycia nieasynchronicznych wyrażeń lambda.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.

W funkcji asynchronicznej await nie może być używany jako identyfikator.Inside of an async function, await cannot be used as an identifier. W związku z tym nie istnieje niejednoznaczność składni między wyrażeniami await i różnymi wyrażeniami obejmującymi identyfikatory.There is therefore no syntactic ambiguity between await-expressions and various expressions involving identifiers. Poza funkcjami asynchronicznymi, await pełni rolę normalnego identyfikatora.Outside of async functions, await acts as a normal identifier.

Argument operacji await_expression nosi nazwę zadanie.The operand of an await_expression is called the task. Reprezentuje operację asynchroniczną, która może być lub nie można jej zakończyć w chwili szacowania await_expression .It represents an asynchronous operation that may or may not be complete at the time the await_expression is evaluated. Celem operatora await jest wstrzymanie wykonywania otaczającej funkcji asynchronicznej do momentu zakończenia oczekującego zadania, a następnie uzyskanie wyniku.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.

Wyrażenia oczekująceAwaitable expressions

Zadanie wyrażenia await jest wymagane, aby można było oczekiwać.The task of an await expression is required to be awaitable. W wyrażeniu t oczekuje się, że występuje jedno z następujących elementów:An expression t is awaitable if one of the following holds:

  • t jest typu czasu kompilacji dynamict is of compile time type dynamic
  • t ma dostępne wystąpienie lub metodę rozszerzającą o nazwie GetAwaiter bez parametrów i bez parametrów typu oraz typem zwracanym A, dla którego wszystkie następujące blokady: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 implementuje interfejs System.Runtime.CompilerServices.INotifyCompletion (dalej znany jako INotifyCompletion dla zwięzłości)A implements the interface System.Runtime.CompilerServices.INotifyCompletion (hereafter known as INotifyCompletion for brevity)
    • A ma dostępną, czytelną Właściwość wystąpienia IsCompleted typu boolA has an accessible, readable instance property IsCompleted of type bool
    • A ma dostępną metodę wystąpienia GetResult bez parametrów i bez parametrów typuA has an accessible instance method GetResult with no parameters and no type parameters

Celem metody GetAwaiter jest uzyskanie oczekiwania dla zadania.The purpose of the GetAwaiter method is to obtain an awaiter for the task. Typ A jest nazywany typem await dla wyrażenia await.The type A is called the awaiter type for the await expression.

Właściwość IsCompleted ma na celu określenie, czy zadanie zostało już ukończone.The purpose of the IsCompleted property is to determine if the task is already complete. Jeśli tak, nie ma potrzeby wstrzymania oceny.If so, there is no need to suspend evaluation.

Celem INotifyCompletion.OnCompleted jest podpisywanie "kontynuacji" do zadania; tj. delegat (typu System.Action), który zostanie wywołany po zakończeniu zadania.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.

Celem metody GetResult jest uzyskanie wyniku zadania po jego zakończeniu.The purpose of the GetResult method is to obtain the outcome of the task once it is complete. Ten wynik może powieść się, prawdopodobnie z wartością wyniku lub może być wyjątek, który jest generowany przez metodę 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.

Klasyfikacja wyrażeń awaitClassification of await expressions

Wyrażenie await t jest sklasyfikowane tak samo jak w przypadku (t).GetAwaiter().GetResult()wyrażenia.The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). W takim przypadku, jeśli typ zwracany GetResult jest void, await_expression jest sklasyfikowany jako Nothing.Thus, if the return type of GetResult is void, the await_expression is classified as nothing. Jeśli ma typ zwracany inny niż void T, await_expression zostanie sklasyfikowany jako wartość typu T.If it has a non-void return type T, the await_expression is classified as a value of type T.

Ocena czasu wykonywania dla wyrażeń awaitRuntime evaluation of await expressions

W czasie wykonywania wyrażenie await t jest oceniane w następujący sposób:At runtime, the expression await t is evaluated as follows:

  • a oczekiwania jest uzyskiwany przez obliczenie (t).GetAwaiter()wyrażenia.An awaiter a is obtained by evaluating the expression (t).GetAwaiter().
  • b bool jest uzyskiwany poprzez obliczenie (a).IsCompletedwyrażenia.A bool b is obtained by evaluating the expression (a).IsCompleted.
  • Jeśli b jest false, Ocena zależy od tego, czy a implementuje interfejs System.Runtime.CompilerServices.ICriticalNotifyCompletion (dalej znany jako ICriticalNotifyCompletion for zwięzłości).If b is false then evaluation depends on whether a implements the interface System.Runtime.CompilerServices.ICriticalNotifyCompletion (hereafter known as ICriticalNotifyCompletion for brevity). To sprawdzanie jest wykonywane w czasie wiązania; tj. w czasie wykonywania, jeśli a ma typ czasu kompilacji dynamici w przeciwnym razie w czasie kompilacji.This check is done at binding time; i.e. at runtime if a has the compile time type dynamic, and at compile time otherwise. Niech r oznacza delegata wznawiania (Iteratory):Let r denote the resumption delegate (Iterators):
    • Jeśli a nie implementuje ICriticalNotifyCompletion, zostanie obliczone wyrażenie (a as (INotifyCompletion)).OnCompleted(r).If a does not implement ICriticalNotifyCompletion, then the expression (a as (INotifyCompletion)).OnCompleted(r) is evaluated.
    • Jeśli a implementuje ICriticalNotifyCompletion, zostanie obliczone wyrażenie (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r).If a does implement ICriticalNotifyCompletion, then the expression (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r) is evaluated.
    • Szacowanie jest zawieszone, a sterowanie jest zwracane do bieżącego obiektu wywołującego funkcji asynchronicznej.Evaluation is then suspended, and control is returned to the current caller of the async function.
  • Bezpośrednio po (jeśli b była true) lub po późniejszym wywołaniu delegata wznawiania (jeśli b była false) zostanie obliczone wyrażenie (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. Jeśli zwraca wartość, ta wartość jest wynikiem await_expression.If it returns a value, that value is the result of the await_expression. W przeciwnym razie wynik nie będzie miał żadnego skutku.Otherwise the result is nothing.

Implementacja metody interfejsu w programie await INotifyCompletion.OnCompleted i ICriticalNotifyCompletion.UnsafeOnCompleted powinna spowodować, że delegat r być wywoływany najwyżej raz.An awaiter's implementation of the interface methods INotifyCompletion.OnCompleted and ICriticalNotifyCompletion.UnsafeOnCompleted should cause the delegate r to be invoked at most once. W przeciwnym razie zachowanie otaczającej funkcji asynchronicznej jest niezdefiniowane.Otherwise, the behavior of the enclosing async function is undefined.

Operatory arytmetyczneArithmetic operators

Operatory *, /, %, +i - są określane jako operatory arytmetyczne.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
    ;

Jeśli argument operacji operatora arytmetycznego ma typ czasu kompilacji dynamic, wyrażenie jest dynamicznie powiązane (powiązanie dynamiczne).If an operand of an arithmetic operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). W takim przypadku typ czasu kompilacji wyrażenia jest dynamic, a rozwiązanie opisane poniżej będzie odbywać się w czasie wykonywania przy użyciu typu czasu wykonywania tych operandów, które mają dynamictypu kompilacja.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.

Operator mnożeniaMultiplication operator

Aby można było wykonać operację x * y, do wybrania implementacji określonego operatora jest stosowana metoda rozpoznawania przeciążenia operatora binarnego (rozpoznawanie przeciążeń operatora binarnego).For an operation of the form x * y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Operandy są konwertowane na typy parametrów wybranego operatora, a typ wyniku jest typem zwracanym operatora.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.

Poniżej przedstawiono wstępnie zdefiniowane operatory mnożenia.The predefined multiplication operators are listed below. Operator All Oblicza iloczyn x i y.The operators all compute the product of x and y.

  • Mnożenie całkowite: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);
    

    W kontekście checked, jeśli produkt znajduje się poza zakresem typu wyników, zostanie zgłoszony System.OverflowException.In a checked context, if the product is outside the range of the result type, a System.OverflowException is thrown. W kontekście unchecked przepełnienia nie są raportowane i wszelkie znaczące bity o dużej kolejności poza zakresem typu wynik są odrzucane.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Mnożenie zmiennoprzecinkowe:Floating-point multiplication:

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

    Produkt jest obliczany zgodnie z regułami arytmetycznymi IEEE 754.The product is computed according to the rules of IEEE 754 arithmetic. W poniższej tabeli przedstawiono wyniki wszystkich możliwych kombinacji niezerowych wartości, zer, nieskończoności i NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. W tabeli x i y są dodatnimi skończonemi wartościami.In the table, x and y are positive finite values. z jest wynikiem x * y.z is the result of x * y. Jeśli wynik jest za duży dla typu docelowego, z jest nieskończoność.If the result is too large for the destination type, z is infinity. Jeśli wynik jest za mały dla typu docelowego, z wynosi zero.If the result is too small for the destination type, z is zero.

    + y+y -y-y +0+0 -0-0 + plik inf+inf -inf-inf NaNNaN
    +x+x +z+z -z-z +0+0 -0-0 + plik inf+inf -inf-inf NaNNaN
    {1>-<1}x-x -z-z +z+z -0-0 +0+0 -inf-inf + plik 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
    + plik inf+inf + plik inf+inf -inf-inf NaNNaN NaNNaN + plik inf+inf -inf-inf NaNNaN
    -inf-inf -inf-inf + plik inf+inf NaNNaN NaNNaN -inf-inf + plik inf+inf NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Mnożenie dziesiętne:Decimal multiplication:

    decimal operator *(decimal x, decimal y);
    

    Jeśli wartość wyniku jest zbyt duża, aby reprezentować w formacie decimal, zostanie zgłoszony System.OverflowException.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Jeśli wartość wynikowa jest zbyt mała do reprezentowania w formacie decimal, wynik wynosi zero.If the result value is too small to represent in the decimal format, the result is zero. Skala wyniku, przed zaokrągleniem, jest sumą skali dwóch operandów.The scale of the result, before any rounding, is the sum of the scales of the two operands.

    Mnożenie dziesiętne jest równoważne użyciu operator mnożenia typu System.Decimal.Decimal multiplication is equivalent to using the multiplication operator of type System.Decimal.

Operator dzieleniaDivision operator

Aby można było wykonać operację x / y, do wybrania implementacji określonego operatora jest stosowana metoda rozpoznawania przeciążenia operatora binarnego (rozpoznawanie przeciążeń operatora binarnego).For an operation of the form x / y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Operandy są konwertowane na typy parametrów wybranego operatora, a typ wyniku jest typem zwracanym operatora.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.

Poniżej znajdują się wstępnie zdefiniowane operatory dzielenia.The predefined division operators are listed below. Operator All Oblicza iloraz x i y.The operators all compute the quotient of x and y.

  • Dzielenie liczb całkowitych: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);
    

    Jeśli wartość argumentu po prawej stronie jest równa zero, zostanie zgłoszony System.DivideByZeroException.If the value of the right operand is zero, a System.DivideByZeroException is thrown.

    Podział zaokrągla wynik do zera.The division rounds the result towards zero. W związku z tym wartość bezwzględna wyniku to największa możliwa liczba całkowita, która jest mniejsza lub równa wartości bezwzględnej ilorazu dwóch operandów.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. Wynik ma wartość zero lub wartość dodatnią, gdy dwa operandy mają ten sam znak i zero lub wartość ujemną, gdy dwa operandy mają przeciwne znaki.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.

    Jeśli Lewy argument operacji jest najmniejszym możliwym do zaprezentowania int lub long wartość, a prawy operand jest -1, występuje przepełnienie.If the left operand is the smallest representable int or long value and the right operand is -1, an overflow occurs. W kontekście checked powoduje to System.ArithmeticException (lub jego podklasę) do wyrzucania.In a checked context, this causes a System.ArithmeticException (or a subclass thereof) to be thrown. W kontekście unchecked jest to zdefiniowane przez implementację w zależności od tego, czy System.ArithmeticException (lub podklasa tego elementu) jest zgłaszany, czy przepełnienie zostanie nieraportowane z wartością uzyskaną dla lewego operandu.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.

  • Dzielenie zmiennoprzecinkowe:Floating-point division:

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

    Iloraz jest obliczany zgodnie z regułami arytmetycznymi IEEE 754.The quotient is computed according to the rules of IEEE 754 arithmetic. W poniższej tabeli przedstawiono wyniki wszystkich możliwych kombinacji niezerowych wartości, zer, nieskończoności i NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. W tabeli x i y są dodatnimi skończonemi wartościami.In the table, x and y are positive finite values. z jest wynikiem x / y.z is the result of x / y. Jeśli wynik jest za duży dla typu docelowego, z jest nieskończoność.If the result is too large for the destination type, z is infinity. Jeśli wynik jest za mały dla typu docelowego, z wynosi zero.If the result is too small for the destination type, z is zero.

    + y+y -y-y +0+0 -0-0 + plik inf+inf -inf-inf NaNNaN
    +x+x +z+z -z-z + plik inf+inf -inf-inf +0+0 -0-0 NaNNaN
    {1>-<1}x-x -z-z +z+z -inf-inf + plik 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
    + plik inf+inf + plik inf+inf -inf-inf + plik inf+inf -inf-inf NaNNaN NaNNaN NaNNaN
    -inf-inf -inf-inf + plik inf+inf -inf-inf + plik inf+inf NaNNaN NaNNaN NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Dzielenie dziesiętne:Decimal division:

    decimal operator /(decimal x, decimal y);
    

    Jeśli wartość argumentu po prawej stronie jest równa zero, zostanie zgłoszony System.DivideByZeroException.If the value of the right operand is zero, a System.DivideByZeroException is thrown. Jeśli wartość wyniku jest zbyt duża, aby reprezentować w formacie decimal, zostanie zgłoszony System.OverflowException.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Jeśli wartość wynikowa jest zbyt mała do reprezentowania w formacie decimal, wynik wynosi zero.If the result value is too small to represent in the decimal format, the result is zero. Skala wyniku jest najmniejszą skalą, która będzie zachować wynik równy najbliższej wartości dziesiętnej możliwej do zaprezentowania do rzeczywistego wyniku matematycznego.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.

    Dzielenie dziesiętne jest równoważne użyciu operator dzielenia typu System.Decimal.Decimal division is equivalent to using the division operator of type System.Decimal.

Operator resztyRemainder operator

Aby można było wykonać operację x % y, do wybrania implementacji określonego operatora jest stosowana metoda rozpoznawania przeciążenia operatora binarnego (rozpoznawanie przeciążeń operatora binarnego).For an operation of the form x % y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Operandy są konwertowane na typy parametrów wybranego operatora, a typ wyniku jest typem zwracanym operatora.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.

Poniżej przedstawiono wstępnie zdefiniowane operatory pozostałej reszty.The predefined remainder operators are listed below. Operator All obliczy resztę podziału między x i y.The operators all compute the remainder of the division between x and y.

  • Reszta całkowita: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);
    

    Wynik x % y jest wartością wygenerowaną przez x - (x / y) * y.The result of x % y is the value produced by x - (x / y) * y. Jeśli y wynosi zero, zostanie zgłoszony System.DivideByZeroException.If y is zero, a System.DivideByZeroException is thrown.

    Jeśli Lewy argument operacji jest najmniejszą wartością int lub long, a prawy operand jest -1, zostanie zgłoszony System.OverflowException.If the left operand is the smallest int or long value and the right operand is -1, a System.OverflowException is thrown. W żadnym przypadku x % y zgłosić wyjątek, w którym x / y nie zgłosić wyjątku.In no case does x % y throw an exception where x / y would not throw an exception.

  • Pozostała liczba zmiennoprzecinkowa:Floating-point remainder:

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

    W poniższej tabeli przedstawiono wyniki wszystkich możliwych kombinacji niezerowych wartości, zer, nieskończoności i NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. W tabeli x i y są dodatnimi skończonemi wartościami.In the table, x and y are positive finite values. z jest wynikiem x % y i jest obliczany jako x - n * y, gdzie n jest największą możliwą liczbą całkowitą, która jest mniejsza lub równa 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. Ta metoda przetwarzania reszty jest analogiczna do tego, który jest używany przez operandy całkowite, ale różni się od definicji IEEE 754 (w której n jest liczbą całkowitą najbliżej 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 + plik inf+inf -inf-inf NaNNaN
    +x+x +z+z +z+z NaNNaN NaNNaN xx xx NaNNaN
    {1>-<1}x-x -z-z -z-z NaNNaN NaNNaN {1>-<1}x-x {1>-<1}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
    + plik 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
  • Reszta dziesiętna:Decimal remainder:

    decimal operator %(decimal x, decimal y);
    

    Jeśli wartość argumentu po prawej stronie jest równa zero, zostanie zgłoszony System.DivideByZeroException.If the value of the right operand is zero, a System.DivideByZeroException is thrown. Skala wyniku przed zaokrągleniem jest większa od skali dwóch operandów, a znak wyniku, jeśli wartość jest różna od zera, jest taka sama jak w przypadku 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.

    Reszta dziesiętna jest równoważna z użyciem operatora pozostałej części typu System.Decimal.Decimal remainder is equivalent to using the remainder operator of type System.Decimal.

Operator dodawaniaAddition operator

Aby można było wykonać operację x + y, do wybrania implementacji określonego operatora jest stosowana metoda rozpoznawania przeciążenia operatora binarnego (rozpoznawanie przeciążeń operatora binarnego).For an operation of the form x + y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Operandy są konwertowane na typy parametrów wybranego operatora, a typ wyniku jest typem zwracanym operatora.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.

Wstępnie zdefiniowane operatory dodawania są wymienione poniżej.The predefined addition operators are listed below. W przypadku typów liczbowych i wyliczeniowych wstępnie zdefiniowane operatory dodawania obliczają sumę dwóch argumentów operacji.For numeric and enumeration types, the predefined addition operators compute the sum of the two operands. Gdy jeden lub oba operandy są typu String, wstępnie zdefiniowane operatory dodawania łączą ciąg reprezentujący operandy.When one or both operands are of type string, the predefined addition operators concatenate the string representation of the operands.

  • Dodanie liczby całkowitej: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);
    

    W kontekście checked, jeśli suma jest poza zakresem typu wyników, zostanie zgłoszony System.OverflowException.In a checked context, if the sum is outside the range of the result type, a System.OverflowException is thrown. W kontekście unchecked przepełnienia nie są raportowane i wszelkie znaczące bity o dużej kolejności poza zakresem typu wynik są odrzucane.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Dodawanie zmiennoprzecinkowe:Floating-point addition:

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

    Suma jest obliczana zgodnie z regułami arytmetycznymi IEEE 754.The sum is computed according to the rules of IEEE 754 arithmetic. W poniższej tabeli przedstawiono wyniki wszystkich możliwych kombinacji niezerowych wartości, zer, nieskończoności i NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. W tabeli x i y są wartość różną od zera, a z jest wynikiem x + y.In the table, x and y are nonzero finite values, and z is the result of x + y. Jeśli x i y mają taką samą wartość, ale przeciwległe znaki, z to dodatnia wartość zero.If x and y have the same magnitude but opposite signs, z is positive zero. Jeśli x + y jest zbyt duża do reprezentowania w typie docelowym, z jest nieskończoność z tym samym znakiem, co 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.

    {1>y<1}y +0+0 -0-0 + plik inf+inf -inf-inf NaNNaN
    xx zz xx xx + plik inf+inf -inf-inf NaNNaN
    +0+0 {1>y<1}y +0+0 +0+0 + plik inf+inf -inf-inf NaNNaN
    -0-0 {1>y<1}y +0+0 -0-0 + plik inf+inf -inf-inf NaNNaN
    + plik inf+inf + plik inf+inf + plik inf+inf + plik inf+inf + plik inf+inf NaNNaN NaNNaN
    -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN -inf-inf NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Dodawanie dziesiętne:Decimal addition:

    decimal operator +(decimal x, decimal y);
    

    Jeśli wartość wyniku jest zbyt duża, aby reprezentować w formacie decimal, zostanie zgłoszony System.OverflowException.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Skala wyniku przed zaokrąglaniem jest większym skalą dwóch operandów.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    Dodawanie dziesiętne jest równoznaczne z użyciem operatora dodawania typu System.Decimal.Decimal addition is equivalent to using the addition operator of type System.Decimal.

  • Dodawanie wyliczenia.Enumeration addition. Każdy typ wyliczeniowy niejawnie udostępnia następujące wstępnie zdefiniowane operatory, gdzie E jest typem wyliczenia, a U jest podstawowym typem 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);
    

    W czasie wykonywania te operatory są oceniane dokładnie jako (E)((U)x + (U)y).At run-time these operators are evaluated exactly as (E)((U)x + (U)y).

  • Łączenie ciągów:String concatenation:

    string operator +(string x, string y);
    string operator +(string x, object y);
    string operator +(object x, string y);
    

    Te przeciążenia operatora + binarnego wykonują łączenie ciągów.These overloads of the binary + operator perform string concatenation. Jeśli argument operacji łączenia ciągów jest null, zostanie zastąpiony pusty ciąg.If an operand of string concatenation is null, an empty string is substituted. W przeciwnym razie dowolny argument niebędący ciągiem jest konwertowany na reprezentację ciągu przez wywoływanie metody wirtualnej ToString dziedziczonej z typu object.Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. Jeśli ToString zwraca null, zostanie zastąpiony pusty ciąg.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
        }
    }
    

    Wynik operatora łączenia ciągów jest ciągiem zawierającym znaki operandu po lewej stronie, po którym następuje znak operandu z prawej strony. Operator łączenia ciągów nigdy nie zwraca wartości null. Jeśli nie jest dostępna wystarczająca ilość pamięci do przydzielenia ciągu powstałego, może zostać zgłoszony System.OutOfMemoryException.A System.OutOfMemoryException may be thrown if there is not enough memory available to allocate the resulting string.

  • Delegowanie kombinacji.Delegate combination. Każdy typ delegata niejawnie udostępnia następujący wstępnie zdefiniowany operator, gdzie D jest typem delegata:Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator +(D x, D y);
    

    Operator + binarnych wykonuje kombinację delegata, gdy oba operandy mają typ delegata D.The binary + operator performs delegate combination when both operands are of some delegate type D. (Jeśli operandy mają różne typy delegatów, występuje błąd czasu powiązania). Jeśli pierwszy operand jest null, wynik operacji jest wartością drugiego operandu (nawet jeśli jest również 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). W przeciwnym razie, jeśli drugi operand jest null, wynikiem operacji jest wartość pierwszego operandu.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. W przeciwnym razie wynik operacji jest nowym wystąpieniem delegata, które wywołuje pierwszy operand, a następnie wywołuje drugi 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. Aby zapoznać się z przykładami kombinacji delegatów, zobacz operator odejmowania i delegowanie wywołania.For examples of delegate combination, see Subtraction operator and Delegate invocation. Ponieważ System.Delegate nie jest typem delegata, operator + nie jest dla niego zdefiniowany.Since System.Delegate is not a delegate type, operator + is not defined for it.

Operator odejmowaniaSubtraction operator

Aby można było wykonać operację x - y, do wybrania implementacji określonego operatora jest stosowana metoda rozpoznawania przeciążenia operatora binarnego (rozpoznawanie przeciążeń operatora binarnego).For an operation of the form x - y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Operandy są konwertowane na typy parametrów wybranego operatora, a typ wyniku jest typem zwracanym operatora.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.

Poniżej przedstawiono wstępnie zdefiniowane operatory odejmowania.The predefined subtraction operators are listed below. Operatory wszystkie odjęcie y od x.The operators all subtract y from x.

  • Odejmowanie całkowite: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);
    

    W kontekście checked, jeśli różnica jest poza zakresem typu wyników, generowany jest System.OverflowException.In a checked context, if the difference is outside the range of the result type, a System.OverflowException is thrown. W kontekście unchecked przepełnienia nie są raportowane i wszelkie znaczące bity o dużej kolejności poza zakresem typu wynik są odrzucane.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Odejmowanie zmiennoprzecinkowe:Floating-point subtraction:

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

    Różnica jest obliczana zgodnie z regułami arytmetycznymi IEEE 754.The difference is computed according to the rules of IEEE 754 arithmetic. W poniższej tabeli przedstawiono wyniki wszystkich możliwych kombinacji niezerowych wartości, zer, nieskończoności i NaNs.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaNs. W tabeli x i y są wartość różną od zera, a z jest wynikiem x - y.In the table, x and y are nonzero finite values, and z is the result of x - y. Jeśli x i y są równe, z jest dodatnią wartością zerową.If x and y are equal, z is positive zero. Jeśli x - y jest zbyt duża do reprezentowania w typie docelowym, z jest nieskończoność z tym samym znakiem, co 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.

    {1>y<1}y +0+0 -0-0 + plik inf+inf -inf-inf NaNNaN
    xx zz xx xx -inf-inf + plik inf+inf NaNNaN
    +0+0 -y-y +0+0 +0+0 -inf-inf + plik inf+inf NaNNaN
    -0-0 -y-y -0-0 +0+0 -inf-inf + plik inf+inf NaNNaN
    + plik inf+inf + plik inf+inf + plik inf+inf + plik inf+inf NaNNaN + plik inf+inf NaNNaN
    -inf-inf -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Odejmowanie dziesiętne:Decimal subtraction:

    decimal operator -(decimal x, decimal y);
    

    Jeśli wartość wyniku jest zbyt duża, aby reprezentować w formacie decimal, zostanie zgłoszony System.OverflowException.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Skala wyniku przed zaokrąglaniem jest większym skalą dwóch operandów.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    Odejmowanie dziesiętne jest równoważne użyciu operator odejmowania typu System.Decimal.Decimal subtraction is equivalent to using the subtraction operator of type System.Decimal.

  • Odejmowanie wyliczenia.Enumeration subtraction. Każdy typ wyliczeniowy niejawnie udostępnia następujący wstępnie zdefiniowany operator, gdzie E jest typem wyliczenia, a U jest podstawowym typem 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);
    

    Ten operator jest oceniany dokładnie jako (U)((U)x - (U)y).This operator is evaluated exactly as (U)((U)x - (U)y). Innymi słowy operator oblicza różnicę między wartościami porządkowymi x i y, a typ wyniku jest podstawowym typem wyliczenia.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);
    

    Ten operator jest oceniany dokładnie jako (E)((U)x - y).This operator is evaluated exactly as (E)((U)x - y). Innymi słowy, operator odejmuje wartość od podstawowego typu wyliczenia, która zwraca wartość wyliczenia.In other words, the operator subtracts a value from the underlying type of the enumeration, yielding a value of the enumeration.

  • Usuwanie delegata.Delegate removal. Każdy typ delegata niejawnie udostępnia następujący wstępnie zdefiniowany operator, gdzie D jest typem delegata:Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator -(D x, D y);
    

    Operator - binarnych wykonuje usuwanie delegata, gdy oba operandy mają typ delegata D.The binary - operator performs delegate removal when both operands are of some delegate type D. Jeśli operandy mają różne typy delegatów, wystąpi błąd w czasie trwania powiązania.If the operands have different delegate types, a binding-time error occurs. Jeśli pierwszy operand jest null, wynik operacji jest null.If the first operand is null, the result of the operation is null. W przeciwnym razie, jeśli drugi operand jest null, wynikiem operacji jest wartość pierwszego operandu.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. W przeciwnym razie oba operandy reprezentują listy wywołań (deklaracje delegatów), które mają co najmniej jeden wpis, a wynik jest nową listą wywołania składającą się z listy pierwszego operandu, z której usunięto wpisy drugiego operandu, pod warunkiem, że lista drugi operand jest właściwą ciągłą podlistą pierwszego elementu.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. (Aby określić równość podlistów, odpowiednie wpisy są porównywane jako dla operatora równości delegata (operatorzy równości). W przeciwnym razie wynik jest wartością operandu po lewej stronie.(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. Żadna z list argumentów operacji nie została zmieniona w procesie.Neither of the operands' lists is changed in the process. Jeśli drugi operand jest zgodny z wieloma podlistami ciągłego wpisów na liście pierwszego operandu, zostanie usunięta podlista z prawej strony.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. Jeśli usunięcie spowoduje powstanie pustej listy, wynik jest null.If removal results in an empty list, the result is null. Na przykład: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
        }
    }
    

Operatory przesunięciaShift operators

Operatory << i >> służą do wykonywania operacji przesunięcia bitowego.The << and >> operators are used to perform bit shifting operations.

shift_expression
    : additive_expression
    | shift_expression '<<' additive_expression
    | shift_expression right_shift additive_expression
    ;

Jeśli argument operacji shift_expression ma typ czasu kompilacji dynamic, wyrażenie jest dynamicznie powiązane (powiązanie dynamiczne).If an operand of a shift_expression has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). W takim przypadku typ czasu kompilacji wyrażenia jest dynamic, a rozwiązanie opisane poniżej będzie odbywać się w czasie wykonywania przy użyciu typu czasu wykonywania tych operandów, które mają dynamictypu kompilacja.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.

W przypadku operacji x << count lub x >> count, rozpoznawanie przeciążenia operatora binarnego (rozpoznawanie przeciążenia operatora binarnego) jest stosowane w celu wybrania implementacji określonego operatora.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. Operandy są konwertowane na typy parametrów wybranego operatora, a typ wyniku jest typem zwracanym operatora.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.

Podczas deklarowania przeciążonego operatora przesunięcia typ pierwszego operandu musi być zawsze klasą lub strukturą zawierającą deklarację operatora, a typ drugiego operandu musi być zawsze 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.

Poniżej przedstawiono wstępnie zdefiniowane operatory przesunięcia.The predefined shift operators are listed below.

  • Przesuń w lewo: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);
    

    Operator << przesuwa x pozostawione przez liczbę bitów obliczanych w sposób opisany poniżej.The << operator shifts x left by a number of bits computed as described below.

    Bity o dużej kolejności poza zakresem wyników x są odrzucane, pozostałe bity są przesunięte w lewo, a puste pozycje bitu w kolejności są ustawione na zero.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.

  • Przesuń w prawo: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);
    

    Operator >> przesuwa x bezpośrednio przez liczbę bitów obliczanych w sposób opisany poniżej.The >> operator shifts x right by a number of bits computed as described below.

    Gdy x jest typu int lub long, x bity o niskiej kolejności są odrzucane, pozostałe bity są przesunięte w prawo, a puste pozycje bitowe są ustawiane na zero, jeśli x nie są ujemne i są ustawione na jeden, jeśli x jest ujemna.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.

    Gdy x jest typu uint lub ulong, x bity o niskiej kolejności są odrzucane, pozostałe bity są przesunięte w prawo, a puste pozycje bitu w kolejności są ustawione na zero.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.

Dla wstępnie zdefiniowanych operatorów liczba bitów do przesunięcia jest obliczana w następujący sposób:For the predefined operators, the number of bits to shift is computed as follows:

  • Gdy typ x jest int lub uint, liczba przesunięć jest określona przez pięć bitów count.When the type of x is int or uint, the shift count is given by the low-order five bits of count. Innymi słowy, licznik przesunięć jest obliczany na podstawie count & 0x1F.In other words, the shift count is computed from count & 0x1F.
  • Gdy typ x jest long lub ulong, liczba przesunięć jest podawana w niskiej kolejności dla count.When the type of x is long or ulong, the shift count is given by the low-order six bits of count. Innymi słowy, licznik przesunięć jest obliczany na podstawie count & 0x3F.In other words, the shift count is computed from count & 0x3F.

Jeśli wynikowa liczba przesunięć jest równa zero, operatory przesunięcia po prostu zwracają wartość x.If the resulting shift count is zero, the shift operators simply return the value of x.

Operacje przesunięcia nigdy nie powodują przepełniania i tworzą te same wyniki w kontekście checked i unchecked.Shift operations never cause overflows and produce the same results in checked and unchecked contexts.

Gdy argument operacji po lewej stronie operatora >> ma typ całkowity ze znakiem, operator wykonuje arytmetyczne przesunięcie w prawo, co powoduje, że wartość najbardziej znaczącego bitu (bit znaku) operandu jest propagowana do pustych pozycji w kolejności całkowitej.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. Gdy argument operacji po lewej stronie operatora >> jest typu całkowitego bez znaku, operator wykonuje logiczne przesunięcie w prawo, co powoduje, że puste pozycje bitu o wysokiej kolejności są zawsze ustawione na zero.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. Aby wykonać odwrotną operację, która została wywnioskowana z typu operandu, można użyć jawnych rzutowania.To perform the opposite operation of that inferred from the operand type, explicit casts can be used. Na przykład jeśli x jest zmienną typu int, operacja unchecked((int)((uint)x >> y)) wykonuje logiczne przesunięcie w prawo od 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.

Operatory relacyjne i testowe typuRelational and type-testing operators

Operatory ==, !=, <, >, <=, >=, is i as są nazywane operatorami relacyjnymi i testowymi.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
    ;

Operator is jest opisany w operatorze is i operator as został opisany w operatorze as.The is operator is described in The is operator and the as operator is described in The as operator.

Operatory ==, !=, <, >, <= i >=operatorami porównania.The ==, !=, <, >, <= and >= operators are comparison operators.

Jeśli argument operacji operatora porównania ma typ czasu kompilacji dynamic, wyrażenie jest dynamicznie powiązane (powiązanie dynamiczne).If an operand of a comparison operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). W takim przypadku typ czasu kompilacji wyrażenia jest dynamic, a rozwiązanie opisane poniżej będzie odbywać się w czasie wykonywania przy użyciu typu czasu wykonywania tych operandów, które mają dynamictypu kompilacja.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.

W przypadku operacji w formularzu x op y, gdzie op jest operatorem porównania, do wybrania implementacji określonego operatora jest stosowane rozpoznawanie przeciążenia (rozpoznawanie przeciążeń operatora binarnego).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. Operandy są konwertowane na typy parametrów wybranego operatora, a typ wyniku jest typem zwracanym operatora.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.

Wstępnie zdefiniowane operatory porównania są opisane w poniższych sekcjach.The predefined comparison operators are described in the following sections. Wszystkie wstępnie zdefiniowane operatory porównania zwracają wynik typu bool, zgodnie z opisem w poniższej tabeli.All predefined comparison operators return a result of type bool, as described in the following table.

OperacjaOperation wynikResult
x == y true, jeśli x jest równe y, false w przeciwnym razietrue if x is equal to y, false otherwise
x != y true, jeśli x nie jest równe y, false w przeciwnym razietrue if x is not equal to y, false otherwise
x < y true, jeśli x jest mniejsza niż y, false w przeciwnym razietrue if x is less than y, false otherwise
x > y true, jeśli x jest większa niż y, false w przeciwnym razietrue if x is greater than y, false otherwise
x <= y true, jeśli x jest mniejsze niż lub równe y, false w przeciwnym razietrue if x is less than or equal to y, false otherwise
x >= y true, jeśli x jest większy lub równy y, false w przeciwnym razietrue if x is greater than or equal to y, false otherwise

Operatory porównywania liczb całkowitychInteger comparison operators

Wstępnie zdefiniowane Operatory porównywania liczb całkowitych to: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);

Każdy z tych operatorów porównuje wartości liczbowe dwóch argumentów operacji i zwraca bool wartość, która wskazuje, czy określona relacja jest true czy 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.

Operatory porównania zmiennoprzecinkowegoFloating-point comparison operators

Wstępnie zdefiniowane operatory porównania zmiennoprzecinkowego to: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);

Operatory porównują operandy zgodnie z regułami standardu IEEE 754:The operators compare the operands according to the rules of the IEEE 754 standard:

  • Jeśli każdy operand jest NaN, wynik jest false dla wszystkich operatorów z wyjątkiem !=, dla których wynik jest true.If either operand is NaN, the result is false for all operators except !=, for which the result is true. Dla każdego z dwóch operandów x != y zawsze daje ten sam wynik co !(x == y).For any two operands, x != y always produces the same result as !(x == y). Jeśli jednak jeden lub oba operandy są NaN, operatory <, >, <=i >= nie generują tych samych wyników co logiczne Negacja operatora przeciwległego.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. Na przykład jeśli jeden z x i y ma wartość NaN, x < y jest false, ale !(x >= y) jest true.For example, if either of x and y is NaN, then x < y is false, but !(x >= y) is true.

  • Gdy żaden operand nie jest NaN, operatory porównują wartości dwóch argumentów zmiennoprzecinkowych w odniesieniu do kolejnościWhen 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
    

    gdzie min i max to najmniejsza i największa wartość dodatnia wartości, które mogą być reprezentowane w danym formacie zmiennoprzecinkowym.where min and max are the smallest and largest positive finite values that can be represented in the given floating-point format. Znaczące efekty tego porządku to:Notable effects of this ordering are:

    • Ujemne i dodatnie zera są uważane za równe.Negative and positive zeros are considered equal.
    • Ujemna nieskończoność jest uznawana za mniej niż wszystkie inne wartości, ale jest równa innej nieskończoności ujemnej.A negative infinity is considered less than all other values, but equal to another negative infinity.
    • Nieskończoność dodatnia jest uznawana za większą niż wszystkie inne wartości, ale jest równa innej nieskończoności dodatniej.A positive infinity is considered greater than all other values, but equal to another positive infinity.

Operatory porównywania dziesiętnegoDecimal comparison operators

Wstępnie zdefiniowane Operatory porównywania dziesiętnego to: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);

Każdy z tych operatorów porównuje wartości liczbowe dwóch argumentów operacji dziesiętnych i zwraca bool wartość, która wskazuje, czy określona relacja jest true czy 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. Każde porównanie dziesiętne jest równoważne użyciu odpowiadającego operatora relacyjnego lub równości typu System.Decimal.Each decimal comparison is equivalent to using the corresponding relational or equality operator of type System.Decimal.

Operatory równości wartości logicznychBoolean equality operators

Wstępnie zdefiniowane operatory równości wartości logicznych to:The predefined boolean equality operators are:

bool operator ==(bool x, bool y);
bool operator !=(bool x, bool y);

Wynik == jest true, jeśli zarówno x, jak i ytrue lub w przypadku x obu y i false.The result of == is true if both x and y are true or if both x and y are false. W przeciwnym razie wynik jest false.Otherwise, the result is false.

Wynik != jest false, jeśli zarówno x, jak i ytrue lub w przypadku x obu y i false.The result of != is false if both x and y are true or if both x and y are false. W przeciwnym razie wynik jest true.Otherwise, the result is true. Gdy operandy są typu bool, operator != generuje ten sam wynik jako operator ^.When the operands are of type bool, the != operator produces the same result as the ^ operator.

Operatory porównania wyliczeniaEnumeration comparison operators

Każdy typ wyliczeniowy niejawnie udostępnia następujące wstępnie zdefiniowane operatory porównania: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);

Wynik oceny x op y, gdzie x i y są wyrażeniami typu wyliczenia E z typem źródłowym U, a op jest jednym z operatorów porównania, jest dokładnie taka sama jak Ocena ((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). Innymi słowy operatory porównywania typów wyliczeniowych po prostu porównują zasadnicze wartości dwóch operandów.In other words, the enumeration type comparison operators simply compare the underlying integral values of the two operands.

Operatory równości typów referencyjnychReference type equality operators

Zdefiniowane operatory równości typów referencyjnych są następujące:The predefined reference type equality operators are:

bool operator ==(object x, object y);
bool operator !=(object x, object y);

Operatory zwracają wynik porównania dwóch odwołań dla równości lub nierówności.The operators return the result of comparing the two references for equality or non-equality.

Ponieważ wstępnie zdefiniowane operatory równości typu referencyjnego akceptują operandy typu object, mają zastosowanie do wszystkich typów, które nie deklarują odpowiednich operator == i operator != członków.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. Z drugiej strony, wszystkie odpowiednie operatory równości zdefiniowane przez użytkownika skutecznie ukrywają wstępnie zdefiniowane operatory równości typów odwołań.Conversely, any applicable user-defined equality operators effectively hide the predefined reference type equality operators.

Operatory równości wstępnie zdefiniowanego typu referencyjnego wymagają jednego z następujących elementów:The predefined reference type equality operators require one of the following:

  • Oba operandy są wartością typu znanym jako reference_type lub nullliterału.Both operands are a value of a type known to be a reference_type or the literal null. Ponadto jawna konwersja odwołań (jawne konwersje odwołań) istnieje z typu każdego operandu do typu innego operandu.Furthermore, an explicit reference conversion (Explicit reference conversions) exists from the type of either operand to the type of the other operand.
  • Jeden operand jest wartością typu T, gdzie T jest type_parameter , a drugi operand jest nullliterału.One operand is a value of type T where T is a type_parameter and the other operand is the literal null. Ponadto T nie ma ograniczenia typu wartości.Furthermore T does not have the value type constraint.

Jeśli jeden z tych warunków nie jest spełniony, wystąpi błąd w czasie trwania powiązania.Unless one of these conditions are true, a binding-time error occurs. Istotne implikacje tych reguł są następujące:Notable implications of these rules are:

  • Jest to błąd czasu powiązania, który służy do porównywania dwóch odwołań, które są znane jako różne w czasie trwania powiązania.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. Na przykład, jeśli typy czasu powiązania operandów są dwoma typami klas A i B, a jeśli żadna z nich nie A ani nie B, wówczas nie byłoby możliwe, aby dwa operandy odwołują się do tego samego obiektu.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. W rezultacie operacja jest traktowana jako błąd czasu powiązania.Thus, the operation is considered a binding-time error.
  • Wstępnie zdefiniowane operatory równości typu referencyjnego nie zezwalają na porównywanie operandów typu wartości.The predefined reference type equality operators do not permit value type operands to be compared. W związku z tym, chyba że typ struktury deklaruje własne operatory równości, nie można porównać wartości tego typu struktury.Therefore, unless a struct type declares its own equality operators, it is not possible to compare values of that struct type.
  • Operatory równości typu referencyjnego ze wstępnie zdefiniowanymi odwołaniami nigdy nie powodują wykonywania operacji opakowywania dla ich argumentów operacji.The predefined reference type equality operators never cause boxing operations to occur for their operands. Nie będzie to miało znaczenia w przypadku wykonywania takich operacji pakowania, ponieważ odwołania do nowo przydzielonych wystąpień opakowanych będą się różnić od wszystkich innych odwołań.It would be meaningless to perform such boxing operations, since references to the newly allocated boxed instances would necessarily differ from all other references.
  • Jeśli argument operacji typu parametru typu T jest porównywany z null, a typ czasu wykonywania T jest typem wartości, wynik porównania jest 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.

Poniższy przykład sprawdza, czy argument nieograniczonego typu parametru typu jest 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();
        ...
    }
}

Konstrukcja x == null jest dozwolona nawet wtedy, gdy T może reprezentować typ wartości, a wynik jest po prostu zdefiniowany do false, gdy T jest typem wartości.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.

W przypadku operacji w postaci x == y lub x != y, jeśli istnieją odpowiednie operator == lub operator !=, reguły rozpoznawania przeciążenia operatora (rozpoznawania przeciążenia operatora binarnego) będą wybierać ten operator zamiast wstępnie zdefiniowanego operatora równości typu odwołania.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. Jednak zawsze jest możliwe wybranie wstępnie zdefiniowanego operatora równości typów odwołań przez jawne rzutowanie jednego lub obu operandów na typ 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. PrzykładThe 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);
    }
}

tworzy dane wyjścioweproduces the output

True
False
False
False

Zmienne s i t odnoszą się do dwóch odrębnych string wystąpień zawierających te same znaki.The s and t variables refer to two distinct string instances containing the same characters. Pierwsze wyniki porównania True ze względu na to, że wstępnie zdefiniowany operator równości ciągów (Operatory równości ciągów) jest wybierany, gdy oba operandy są typu string.The first comparison outputs True because the predefined string equality operator (String equality operators) is selected when both operands are of type string. Pozostałe porównuje wszystkie False wyjściowe, ponieważ jest wybierany wstępnie zdefiniowany operator równości typów referencyjnych, gdy jeden lub oba operandy są typu 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.

Należy zauważyć, że powyższa technika nie jest istotna dla typów wartości.Note that the above technique is not meaningful for value types. PrzykładThe example

class Test
{
    static void Main() {
        int i = 123;
        int j = 123;
        System.Console.WriteLine((object)i == (object)j);
    }
}

dane wyjściowe False ponieważ rzutowania tworzą odwołania do dwóch oddzielnych wystąpień wartości int opakowanych.outputs False because the casts create references to two separate instances of boxed int values.

Operatory równości ciągówString equality operators

Wstępnie zdefiniowane operatory równości ciągów są:The predefined string equality operators are:

bool operator ==(string x, string y);
bool operator !=(string x, string y);

Dwie string wartości są uważane za równe, gdy spełniony jest jeden z następujących warunków:Two string values are considered equal when one of the following is true:

  • Obie wartości są null.Both values are null.
  • Obie wartości są odwołaniami o wartościach innych niż null do wystąpień ciągów, które mają identyczne długości i identyczne znaki w każdej pozycji znaku.Both values are non-null references to string instances that have identical lengths and identical characters in each character position.

Operatory równości ciągów porównują wartości ciągu, a nie odwołania do ciągu.The string equality operators compare string values rather than string references. Gdy dwa oddzielne wystąpienia ciągu zawierają dokładnie tę samą sekwencję znaków, wartości ciągów są równe, ale odwołania są różne.When two separate string instances contain the exact same sequence of characters, the values of the strings are equal, but the references are different. Zgodnie z opisem w operatorach równości typu referencyjnegooperatory równości typu odwołania mogą służyć do porównywania odwołań ciągów zamiast wartości ciągów.As described in Reference type equality operators, the reference type equality operators can be used to compare string references instead of string values.

Deleguj operatory równościDelegate equality operators

Każdy typ delegata niejawnie udostępnia następujące wstępnie zdefiniowane operatory porównania: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);

Dwa wystąpienia delegatów są uważane za równe w następujący sposób:Two delegate instances are considered equal as follows:

  • Jeśli jedno z wystąpień delegatów jest null, są równe, tylko wtedy, gdy oba są null.If either of the delegate instances is null, they are equal if and only if both are null.
  • Jeśli Delegaty mają różne typy czasu wykonywania, nigdy nie są równe.If the delegates have different run-time type they are never equal.
  • Jeśli oba wystąpienia delegatów mają listę wywołań (deklaracje delegatów), te wystąpienia są równe, gdy i tylko wtedy, gdy ich listy wywołań są takie same, a każdy wpis na liście wywołań jednego z nich jest równy (jak zdefiniowano poniżej) do odpowiadającego wpisu w podanej kolejności na liście wywołań drugiej.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.

Następujące reguły określają równość wpisów listy wywołań:The following rules govern the equality of invocation list entries:

  • Jeśli dwa wpisy listy wywołań odnoszą się do tej samej metody statycznej, wpisy są równe.If two invocation list entries both refer to the same static method then the entries are equal.
  • Jeśli dwa wywołania listy wywołań odnoszą się do tej samej metody niestatycznej w tym samym obiekcie docelowym (zgodnie z definicją przez operatory równości odwołań), wpisy są równe.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.
  • Wpisy listy wywołań uzyskane z oceny semantycznie identyczne anonymous_method_expressions lub lambda_expressions z tym samym (prawdopodobnie pustym) zestawem przechwyconych zewnętrznych wystąpień zmiennych są dozwolone (ale nie są wymagane), aby były równe.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.

Operatory równości i nullEquality operators and null

Operatory == i != zezwalają jednemu operandowi na wartość typu null, a drugi jako literał null, nawet jeśli nie istnieje zdefiniowany lub zdefiniowany przez użytkownika operator (w niepodniesionym lub zniesionym formularzu) dla tej operacji.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.

Dla operacji jednego z formularzyFor an operation of one of the forms

x == null
null == x
x != null
null != x

gdzie x jest wyrażeniem typu dopuszczającego wartość null, jeśli nie można znaleźć odpowiedniego operatora w rozpoznaniu przeciążenia operatora (Rozpoznanie przeciążenia operatora binarnego), wynik jest obliczany na podstawie właściwości 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. W każdym przypadku pierwsze dwa formularze są tłumaczone na !x.HasValue, a ostatnie dwa formularze są tłumaczone na x.HasValue.Specifically, the first two forms are translated into !x.HasValue, and last two forms are translated into x.HasValue.

Operator isThe is operator

Operator is jest używany do dynamicznego sprawdzenia, czy typ obiektu w czasie wykonywania jest zgodny z danym typem.The is operator is used to dynamically check if the run-time type of an object is compatible with a given type. Wynik E is Toperacji, gdzie E jest wyrażeniem, a T jest typem, jest wartością logiczną wskazującą, czy E można pomyślnie skonwertować do typu T przez konwersję odwołania, konwersję z opakowaniem lub konwersję rozpakowywanie.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. Operacja jest szacowana w następujący sposób, gdy argumenty typu zostały zastąpione dla wszystkich parametrów typu:The operation is evaluated as follows, after type arguments have been substituted for all type parameters:

  • Jeśli E jest funkcją anonimową, wystąpi błąd w czasie kompilacjiIf E is an anonymous function, a compile-time error occurs
  • Jeśli E jest grupą metod lub literałem null, jeśli typ E jest typem referencyjnym lub typem dopuszczającym wartość null, a wartością E jest zero, wynik ma wartość 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.
  • W przeciwnym razie niech D reprezentuje typ dynamiczny E w następujący sposób:Otherwise, let D represent the dynamic type of E as follows:
    • Jeśli typ E jest typem referencyjnym, D jest typem czasu wykonywania odwołania wystąpienia przez E.If the type of E is a reference type, D is the run-time type of the instance reference by E.
    • Jeśli typ E jest typem dopuszczającym wartość null, D jest typem podstawowym tego typu dopuszczającego wartość null.If the type of E is a nullable type, D is the underlying type of that nullable type.
    • Jeśli typ E jest typem wartości niedopuszczających wartości null, D jest typem E.If the type of E is a non-nullable value type, D is the type of E.
  • Wynik operacji zależy od D i T w następujący sposób:The result of the operation depends on D and T as follows:
    • Jeśli T jest typem referencyjnym, wynik ma wartość true, jeśli D i T są tego samego typu, jeśli D jest typem referencyjnym i niejawną konwersją referencyjną z D do T istnieje, lub jeśli D jest typem wartości, a konwersja z D do T istnieje.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.
    • Jeśli T jest typem dopuszczającym wartość null, wynik ma wartość true, jeśli D jest typem źródłowym T.If T is a nullable type, the result is true if D is the underlying type of T.
    • Jeśli T jest typem wartości niedopuszczających wartości null, wynik ma wartość true, jeśli D i T są tego samego typu.If T is a non-nullable value type, the result is true if D and T are the same type.
    • W przeciwnym razie wynik ma wartość false.Otherwise, the result is false.

Należy zauważyć, że konwersje zdefiniowane przez użytkownika nie są uznawane za przez operator is.Note that user defined conversions, are not considered by the is operator.

Operator asThe as operator

Operator as jest używany do jawnej konwersji wartości na dany typ referencyjny lub typ dopuszczający wartość null.The as operator is used to explicitly convert a value to a given reference type or nullable type. W przeciwieństwie do wyrażenia CAST (wyrażenia rzutowania) operator as nigdy nie zgłasza wyjątku.Unlike a cast expression (Cast expressions), the as operator never throws an exception. Zamiast tego, jeśli wskazana konwersja nie jest możliwa, obliczona wartość jest null.Instead, if the indicated conversion is not possible, the resulting value is null.

W operacji E as Tformularza E musi być wyrażeniem, a T musi być typem referencyjnym, parametrem typu znanym jako typ referencyjny lub typem dopuszczającym wartość 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. Ponadto co najmniej jeden z następujących elementów musi mieć wartość true lub w przeciwnym razie wystąpi błąd w czasie kompilacji:Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs:

Jeśli typ czasu kompilacji E nie jest dynamic, operacja E as T daje ten sam wynik coIf 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

z tą różnicą, że E jest obliczany tylko raz.except that E is only evaluated once. Kompilator może być oczekiwany do zoptymalizowania E as T wykonywania co najwyżej jednego sprawdzenia typu dynamicznego, w przeciwieństwie do dwóch kontroli typu dynamicznego IMPLIKOWANYCH przez rozszerzenie powyżej.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.

Jeśli typ czasu kompilacji E jest dynamic, w przeciwieństwie do operatora rzutowania, operator as nie jest powiązany dynamicznie (powiązanie dynamiczne).If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound (Dynamic binding). W związku z tym rozwinięcie w tym przypadku jest następujące:Therefore the expansion in this case is:

E is T ? (T)(object)(E) : (T)null

Należy zauważyć, że niektóre konwersje, takie jak konwersje zdefiniowane przez użytkownika, nie są możliwe za pomocą operatora as i powinny być wykonywane przy użyciu wyrażeń rzutowania.Note that some conversions, such as user defined conversions, are not possible with the as operator and should instead be performed using cast expressions.

w przykładzieIn 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 
    }
}

parametr typu T G jest znany jako typ referencyjny, ponieważ ma ograniczenie klasy.the type parameter T of G is known to be a reference type, because it has the class constraint. Nie ma jednak U parametru typu H; w związku z tym użycie operatora as w H jest niedozwolone.The type parameter U of H is not however; hence the use of the as operator in H is disallowed.

Operatory logiczneLogical operators

Operatory &, ^i | są nazywane operatorami logicznymi.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
    ;

Jeśli argument operacji operatora logicznego ma typ czasu kompilacji dynamic, wyrażenie jest dynamicznie powiązane (powiązanie dynamiczne).If an operand of a logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). W takim przypadku typ czasu kompilacji wyrażenia jest dynamic, a rozwiązanie opisane poniżej będzie odbywać się w czasie wykonywania przy użyciu typu czasu wykonywania tych operandów, które mają dynamictypu kompilacja.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.

Aby można było wykonać operację x op y, gdzie op jest jednym z operatorów logicznych, do wybrania implementacji określonego operatora jest stosowana metoda rozpoznawania przeciążenia (rozpoznawanie przeciążeń operatora binarnego).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. Operandy są konwertowane na typy parametrów wybranego operatora, a typ wyniku jest typem zwracanym operatora.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.

Wstępnie zdefiniowane operatory logiczne są opisane w poniższych sekcjach.The predefined logical operators are described in the following sections.

Operatory logiczne IntegerInteger logical operators

Wstępnie zdefiniowane operatory logiczne integer są: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);

Operator & oblicza bitowe logiczne AND dwóch operandów, operator | oblicza bitowe logiczne OR dwóch operandów, a operator ^ oblicza bitową logiczną wyłączną OR dwóch operandów.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. Z tych operacji nie jest możliwe przepełnienie.No overflows are possible from these operations.

Wyliczanie operatorów logicznychEnumeration logical operators

Każdy typ wyliczeniowy E niejawnie udostępnia następujące wstępnie zdefiniowane operatory logiczne: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);

Wynik oceny x op y, gdzie x i y są wyrażeniami typu wyliczenia E z typem źródłowym U, a op jest jednym z operatorów logicznych, jest dokładnie taka sama jak Ocena (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). Innymi słowy operatory logiczne typu wyliczeniowy po prostu wykonują operacje logiczne na podstawowym typie dwóch argumentów operacji.In other words, the enumeration type logical operators simply perform the logical operation on the underlying type of the two operands.

Operatory logiczne (Boolean)Boolean logical operators

Wstępnie zdefiniowane operatory logiczne Boolean to:The predefined boolean logical operators are:

bool operator &(bool x, bool y);
bool operator |(bool x, bool y);
bool operator ^(bool x, bool y);

Wynik x & y jest true, jeśli x i ytrue.The result of x & y is true if both x and y are true. W przeciwnym razie wynik jest false.Otherwise, the result is false.

Wynik x | y jest true, jeśli x lub y jest true.The result of x | y is true if either x or y is true. W przeciwnym razie wynik jest false.Otherwise, the result is false.

Wynik x ^ y jest true, jeśli x jest true i y jest false, lub x jest false i y jest true.The result of x ^ y is true if x is true and y is false, or x is false and y is true. W przeciwnym razie wynik jest false.Otherwise, the result is false. Gdy operandy są typu bool, operator ^ oblicza ten sam wynik jako operator !=.When the operands are of type bool, the ^ operator computes the same result as the != operator.

Logiczne operatory wartości nullNullable boolean logical operators

Typ Boolean dopuszczający wartość null bool? może reprezentować trzy wartości, true, falsei nulli jest koncepcyjnie podobny do typu, który jest używany dla wyrażeń logicznych w 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. Aby upewnić się, że wyniki utworzone przez operatory & i | dla argumentów operacji bool? są spójne z logiką trzech wartości, są dostępne następujące wstępnie zdefiniowane operatory: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);

Poniższa tabela zawiera listę wyników wytwarzanych przez te operatory dla wszystkich kombinacji wartości true, falsei 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

Warunkowe operatory logiczneConditional logical operators

Operatory && i || są nazywane warunkowymi operatorami logicznymi.The && and || operators are called the conditional logical operators. Są one również nazywane operatorami logicznymi "krótkie-obwóding".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
    ;

Operatory && i || są warunkowymi wersjami operatorów & i |:The && and || operators are conditional versions of the & and | operators:

  • x && y operacji odpowiada x & yoperacji, z tą różnicą, że y jest obliczana tylko wtedy, gdy x nie false.The operation x && y corresponds to the operation x & y, except that y is evaluated only if x is not false.
  • x || y operacji odpowiada x | yoperacji, z tą różnicą, że y jest obliczana tylko wtedy, gdy x nie true.The operation x || y corresponds to the operation x | y, except that y is evaluated only if x is not true.

Jeśli argument operacji warunkowego operatora logicznego ma typ czasu kompilacji dynamic, wyrażenie jest dynamicznie powiązane (powiązanie dynamiczne).If an operand of a conditional logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). W takim przypadku typ czasu kompilacji wyrażenia jest dynamic, a rozwiązanie opisane poniżej będzie odbywać się w czasie wykonywania przy użyciu typu czasu wykonywania tych operandów, które mają dynamictypu kompilacja.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.

Operacja x && y lub x || y jest przetwarzana przez zastosowanie rozpoznawania przeciążenia (przeciążanie przeciążenia operatora binarnego), tak jakby operacja była zapisywana x & y lub 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. NastępnieThen,

Nie można bezpośrednio przeciążać warunkowych operatorów logicznych.It is not possible to directly overload the conditional logical operators. Jednak ze względu na to, że warunkowe operatory logiczne są oceniane pod względem zwykłych operatorów logicznych, przeciążenia zwykłych operatorów logicznych są, z pewnymi ograniczeniami, również jako przeciążenia warunkowych operatorów logicznych.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. Opisano to dokładniej w warunkowych operatory logicznej zdefiniowanej przez użytkownika.This is described further in User-defined conditional logical operators.

Logiczne warunkowe operatory logiczneBoolean conditional logical operators

Gdy operandy && lub || są typu boollub gdy operandy są typów, które nie definiują odpowiednich operator & ani operator |, ale definiują konwersje niejawne na bool, operacja jest przetwarzana w następujący sposób: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 operacji jest oceniane jako x ? y : false.The operation x && y is evaluated as x ? y : false. Innymi słowy, x jest najpierw oceniane i konwertowane na booltypu.In other words, x is first evaluated and converted to type bool. Następnie Jeśli x jest true, y jest oceniana i konwertowana na typ booli zostanie to wynik operacji.Then, if x is true, y is evaluated and converted to type bool, and this becomes the result of the operation. W przeciwnym razie wynik operacji jest false.Otherwise, the result of the operation is false.
  • x || y operacji jest oceniane jako x ? true : y.The operation x || y is evaluated as x ? true : y. Innymi słowy, x jest najpierw oceniane i konwertowane na booltypu.In other words, x is first evaluated and converted to type bool. Następnie Jeśli x jest true, wynik operacji jest true.Then, if x is true, the result of the operation is true. W przeciwnym razie y jest oceniane i konwertowane na typ booli zostanie to wynikiem operacji.Otherwise, y is evaluated and converted to type bool, and this becomes the result of the operation.

Operatory logiczne warunkowe zdefiniowane przez użytkownikaUser-defined conditional logical operators

Gdy operandy && lub || są typami, które deklarują odpowiednie operator & zdefiniowane przez użytkownika lub operator |, obie poniższe wartości muszą mieć wartość true, gdzie T jest typem, w którym zadeklarowano wybrany operator: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:

  • Typ zwracany i typ każdego parametru wybranego operatora muszą być T.The return type and the type of each parameter of the selected operator must be T. Innymi słowy operator musi obliczać AND logiczne lub logiczne OR dwóch operandów typu Ti musi zwrócić wynik typu 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 musi zawierać deklaracje operator true i operator false.T must contain declarations of operator true and operator false.

Jeśli jedno z tych wymagań nie zostanie spełnione, występuje błąd w czasie trwania powiązania.A binding-time error occurs if either of these requirements is not satisfied. W przeciwnym razie operacja && lub || jest Szacowana przez połączenie operator true zdefiniowanej przez użytkownika lub operator false z wybranym operatorem zdefiniowanym przez użytkownika:Otherwise, the && or || operation is evaluated by combining the user-defined operator true or operator false with the selected user-defined operator:

  • x && y operacji jest oceniane jako T.false(x) ? x : T.&(x, y), gdzie T.false(x) jest wywołaniem operator false zadeklarowanym w T, a T.&(x, y) to wywołanie wybranej 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 &. Innymi słowy, x jest najpierw oceniane i operator false jest wywoływana w wyniku, aby określić, czy x ma wartość false.In other words, x is first evaluated and operator false is invoked on the result to determine if x is definitely false. Następnie Jeśli x ma wartość false, wynik operacji jest wartością obliczoną wcześniej dla x.Then, if x is definitely false, the result of the operation is the value previously computed for x. W przeciwnym razie y jest oceniane i wybrane operator & są wywoływane na wartości obliczonej wcześniej dla x oraz wartości obliczanej dla y, aby utworzyć wynik operacji.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 operacji jest oceniane jako T.true(x) ? x : T.|(x, y), gdzie T.true(x) jest wywołaniem operator true zadeklarowanym w T, a T.|(x,y) to wywołanie wybranej 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|. Innymi słowy x jest najpierw oceniane i operator true jest wywoływana w wyniku, aby określić, czy x ma wartość "prawda".In other words, x is first evaluated and operator true is invoked on the result to determine if x is definitely true. Następnie Jeśli x ma wartość "prawda", wynik operacji jest wartością obliczoną wcześniej dla x.Then, if x is definitely true, the result of the operation is the value previously computed for x. W przeciwnym razie y jest oceniane i wybrane operator | są wywoływane na wartości obliczonej wcześniej dla x oraz wartości obliczanej dla y, aby utworzyć wynik operacji.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.

W każdej z tych operacji wyrażenie podane przez x jest oceniane tylko raz, a wyrażenie podane przez y nie jest oceniane lub oceniane dokładnie raz.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.

Aby zapoznać się z przykładem typu, który implementuje operator true i operator false, zobacz typ Boolean bazy danych.For an example of a type that implements operator true and operator false, see Database boolean type.

Operator łączenia wartości nullThe null coalescing operator

Operator ?? jest nazywany operatorem łączenia wartości null.The ?? operator is called the null coalescing operator.

null_coalescing_expression
    : conditional_or_expression
    | conditional_or_expression '??' null_coalescing_expression
    ;

Wyrażenie łączenia o wartości null w formularzu a ?? b wymaga, aby a być typu dopuszczającego wartość null lub typ referencyjny.A null coalescing expression of the form a ?? b requires a to be of a nullable type or reference type. Jeśli a ma wartość różną od null, wynik a ?? b jest a; w przeciwnym razie wynik jest b.If a is non-null, the result of a ?? b is a; otherwise, the result is b. Operacja oblicza b tylko wtedy, gdy a ma wartość null.The operation evaluates b only if a is null.

Operator łączenia wartości null jest prawym przyciskiem asocjacyjnym, co oznacza, że operacje są pogrupowane od prawej do lewej.The null coalescing operator is right-associative, meaning that operations are grouped from right to left. Na przykład wyrażenie a ?? b ?? c jest oceniane jako a ?? (b ?? c).For example, an expression of the form a ?? b ?? c is evaluated as a ?? (b ?? c). Ogólnie rzecz biorąc, wyrażenie formularza E1 ?? E2 ?? ... ?? En zwraca pierwsze operandy o wartości innej niż null lub wartość null, jeśli wszystkie operandy mają wartość 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.

Typ wyrażenia a ?? b zależy od tego, które konwersje niejawne są dostępne dla operandów.The type of the expression a ?? b depends on which implicit conversions are available on the operands. W kolejności preferencji typ a ?? b jest A0, Alub B, gdzie A jest typem a (pod warunkiem, że a ma typ), B jest typem b (pod warunkiem, że b ma typ), a A0 jest typem podstawowym A, jeśli A jest typem dopuszczającym wartość null lub A w przeciwnym razie.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. W a ?? b jest przetwarzana w następujący sposób:Specifically, a ?? b is processed as follows:

  • Jeśli A istnieje i nie jest typem dopuszczającym wartość null lub typem referencyjnym, wystąpi błąd w czasie kompilacji.If A exists and is not a nullable type or a reference type, a compile-time error occurs.
  • Jeśli b jest wyrażeniem dynamicznym, typem wyniku jest dynamic.If b is a dynamic expression, the result type is dynamic. W czasie wykonywania a jest najpierw oceniane.At run-time, a is first evaluated. Jeśli a nie ma wartości null, a zostanie przekonwertowana na dynamiczny i zostanie to wynik.If a is not null, a is converted to dynamic, and this becomes the result. W przeciwnym razie b jest oceniane i zostanie to wynik.Otherwise, b is evaluated, and this becomes the result.
  • W przeciwnym razie, jeśli A istnieje i jest typem dopuszczającym wartość null, a niejawna konwersja istnieje z b do A0, typem wyniku jest A0.Otherwise, if A exists and is a nullable type and an implicit conversion exists from b to A0, the result type is A0. W czasie wykonywania a jest najpierw oceniane.At run-time, a is first evaluated. Jeśli a nie ma wartości null, a jest odpakowany do typu A0i zostanie to wynikiem.If a is not null, a is unwrapped to type A0, and this becomes the result. W przeciwnym razie b jest oceniane i konwertowane na typ A0i zostanie to wynikiem.Otherwise, b is evaluated and converted to type A0, and this becomes the result.
  • W przeciwnym razie, jeśli A istnieje i istnieje niejawna konwersja z b do A, typem wyniku jest A.Otherwise, if A exists and an implicit conversion exists from b to A, the result type is A. W czasie wykonywania a jest najpierw oceniane.At run-time, a is first evaluated. Jeśli a nie ma wartości null, a zostanie wynikiem.If a is not null, a becomes the result. W przeciwnym razie b jest oceniane i konwertowane na typ Ai zostanie to wynikiem.Otherwise, b is evaluated and converted to type A, and this becomes the result.
  • W przeciwnym razie, jeśli b ma typ B i istnieje niejawna konwersja z a do B, typem wyniku jest B.Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B. W czasie wykonywania a jest najpierw oceniane.At run-time, a is first evaluated. Jeśli a nie ma wartości null, a jest odpakowany do typu A0 (jeśli A istnieje i dopuszcza wartość null) i konwertowane na typ Bi zostanie to wynik.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. W przeciwnym razie b są oceniane i staną się wynikiem.Otherwise, b is evaluated and becomes the result.
  • W przeciwnym razie a i b są niezgodne, a wystąpi błąd w czasie kompilacji.Otherwise, a and b are incompatible, and a compile-time error occurs.

Operator warunkowyConditional operator

Operator ?: jest nazywany operatorem warunkowym.The ?: operator is called the conditional operator. Jest ona czasem nazywana również operatorem Trzyelementowy.It is at times also called the ternary operator.

conditional_expression
    : null_coalescing_expression
    | null_coalescing_expression '?' expression ':' expression
    ;

Wyrażenie warunkowe formularza b ? x : y najpierw oblicza warunek b.A conditional expression of the form b ? x : y first evaluates the condition b. Następnie Jeśli b jest true, x jest oceniane i zostanie wynikiem operacji.Then, if b is true, x is evaluated and becomes the result of the operation. W przeciwnym razie y są oceniane i staną się wynikiem operacji.Otherwise, y is evaluated and becomes the result of the operation. Wyrażenie warunkowe nigdy nie oblicza jednocześnie x i y.A conditional expression never evaluates both x and y.

Operator warunkowy jest z prawej strony asocjacyjny, co oznacza, że operacje są pogrupowane od prawej do lewej.The conditional operator is right-associative, meaning that operations are grouped from right to left. Na przykład wyrażenie a ? b : c ? d : e jest oceniane jako 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).

Pierwszy operand operatora ?: musi być wyrażeniem, które może być niejawnie konwertowane na boollub wyrażenie typu implementującego 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. Jeśli żadne z tych wymagań nie są spełnione, wystąpi błąd w czasie kompilacji.If neither of these requirements is satisfied, a compile-time error occurs.

Drugi i trzeci operand, x i y, operatora ?: sterują typem wyrażenia warunkowego.The second and third operands, x and y, of the ?: operator control the type of the conditional expression.

  • Jeśli x ma typ X i y ma Y typIf x has type X and y has type Y then
    • Jeśli niejawna konwersja (niejawne konwersje) istnieje z X do Y, ale nie z Y do X, wówczas Y jest typem wyrażenia warunkowego.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.
    • Jeśli niejawna konwersja (niejawne konwersje) istnieje z Y do X, ale nie z X do Y, wówczas X jest typem wyrażenia warunkowego.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.
    • W przeciwnym razie nie można określić typu wyrażenia i występuje błąd czasu kompilacji.Otherwise, no expression type can be determined, and a compile-time error occurs.
  • Jeśli tylko jeden z x i y ma typ, a zarówno x, jak i y, z są niejawnie konwertowane do tego typu, to jest typem wyrażenia warunkowego.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.
  • W przeciwnym razie nie można określić typu wyrażenia i występuje błąd czasu kompilacji.Otherwise, no expression type can be determined, and a compile-time error occurs.

Przetwarzanie wyrażenia warunkowego b ? x : y w czasie wykonywania obejmuje następujące kroki:The run-time processing of a conditional expression of the form b ? x : y consists of the following steps:

  • Najpierw b jest oceniane i bool wartość b jest określana:First, b is evaluated, and the bool value of b is determined:
    • Jeśli niejawna konwersja z typu b na bool istnieje, to niejawna konwersja jest wykonywana w celu utworzenia wartości bool.If an implicit conversion from the type of b to bool exists, then this implicit conversion is performed to produce a bool value.
    • W przeciwnym razie operator true zdefiniowane przez typ b jest wywoływana w celu utworzenia wartości bool.Otherwise, the operator true defined by the type of b is invoked to produce a bool value.
  • Jeśli wartość bool generowana przez krok powyżej jest true, x jest oceniana i konwertowana na typ wyrażenia warunkowego, a tym samym wynik wyrażenia warunkowego.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.
  • W przeciwnym razie y jest oceniane i konwertowane na typ wyrażenia warunkowego, a następnie zostanie wynikiem wyrażenia warunkowego.Otherwise, y is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression.

Wyrażenia funkcji anonimowychAnonymous function expressions

Funkcja anonimowa jest wyrażeniem, które reprezentuje definicję metody "w wierszu".An anonymous function is an expression that represents an "in-line" method definition. Funkcja anonimowa nie ma wartości ani typu w i sama, ale jest możliwa do przekonwertowania na zgodny delegat lub typ drzewa wyrażenia.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. Obliczanie konwersji funkcji anonimowej zależy od typu docelowego konwersji: Jeśli jest to typ delegata, konwersja szacuje się na wartość delegata odwołującą się do metody, która definiuje funkcja anonimowa.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. Jeśli jest to typ drzewa wyrażenia, konwersja szacuje się na drzewo wyrażenia, które reprezentuje strukturę metody jako strukturę obiektu.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.

Z przyczyn historycznych istnieją dwa rodzaje składni funkcji anonimowych, czyli lambda_expressions i anonymous_method_expressions.For historical reasons there are two syntactic flavors of anonymous functions, namely lambda_expressions and anonymous_method_expressions. Do niemal wszystkich celów lambda_expressions są bardziej zwięzłe i bardziej wyraźne niż anonymous_method_expressions, które pozostaną w języku w celu zapewnienia zgodności z poprzednimi wersjami.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
    ;

Operator => ma takie samo pierwszeństwo jak przypisanie (=) i jest skojarzony z prawej strony.The => operator has the same precedence as assignment (=) and is right-associative.

Funkcja anonimowa z modyfikatorem async jest funkcją asynchroniczną i jest zgodna z regułami opisanymi w iteratorach.An anonymous function with the async modifier is an async function and follows the rules described in Iterators.

Parametry funkcji anonimowej w postaci lambda_expression mogą być jawnie lub niejawnie wpisane.The parameters of an anonymous function in the form of a lambda_expression can be explicitly or implicitly typed. Na liście jawnie wpisanych parametrów typ każdego parametru jest jawnie określony.In an explicitly typed parameter list, the type of each parameter is explicitly stated. W przypadku niejawnie wpisanej listy parametrów typy parametrów są wywnioskowane z kontekstu, w którym występuje funkcja anonimowa — w przypadku gdy funkcja anonimowa jest konwertowana na zgodny typ delegata lub typ drzewa wyrażenia, ten typ zapewnia typy parametrów (konwersje funkcji anonimowych).In an implicitly typed parameter list, the types of the parameters are inferred from the context in which the anonymous function occurs—specifically, when the anonymous function is converted to a compatible delegate type or expression tree type, that type provides the parameter types (Anonymous function conversions).

W funkcji anonimowej z pojedynczym niejawnie określonym parametrem, nawiasy można pominąć z listy parametrów.In an anonymous function with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. Innymi słowy, funkcja anonimowa formularzaIn other words, an anonymous function of the form

( param ) => expr

może być skrócony docan be abbreviated to

param => expr

Lista parametrów funkcji anonimowej w postaci anonymous_method_expression jest opcjonalna.The parameter list of an anonymous function in the form of an anonymous_method_expression is optional. W przypadku podaną wartość parametry muszą być jawnie wpisane.If given, the parameters must be explicitly typed. W przeciwnym razie funkcja anonimowa jest konwertowany na delegata z dowolną listą parametrów, która nie zawiera out parametrów.If not, the anonymous function is convertible to a delegate with any parameter list not containing out parameters.

Treść bloku funkcji anonimowej jest osiągalna (punkty końcowe i osiągalność), chyba że funkcja anonimowa występuje wewnątrz nieosiągalnej instrukcji.A block body of an anonymous function is reachable (End points and reachability) unless the anonymous function occurs inside an unreachable statement.

Poniżej przedstawiono kilka przykładów funkcji anonimowych:Some examples of anonymous functions follow below:

x => x + 1                              // Implicitly typed, expression body
x => { return x + 1; }                  // Implicitly typed, statement body
(int x) => x + 1                        // Explicitly typed, expression body
(int x) => { return x + 1; }            // Explicitly typed, statement body
(x, y) => x * y                         // Multiple parameters
() => Console.WriteLine()               // No parameters
async (t1,t2) => await t1 + await t2    // Async
delegate (int x) { return x + 1; }      // Anonymous method expression
delegate { return 1 + 1; }              // Parameter list omitted

Zachowanie lambda_expressions i anonymous_method_expressions jest takie samo, z wyjątkiem następujących punktów:The behavior of lambda_expressions and anonymous_method_expressions is the same except for the following points:

  • anonymous_method_expressions zezwala na całkowite pomijanie listy parametrów, co daje Convertibility do delegowania typów dowolnej listy parametrów wartości.anonymous_method_expressions permit the parameter list to be omitted entirely, yielding convertibility to delegate types of any list of value parameters.
  • lambda_expressions Zezwalaj na pomijanie typów parametrów i wywnioskowane anonymous_method_expressions wymaga jawnego określenia typów parametrów.lambda_expressions permit parameter types to be omitted and inferred whereas anonymous_method_expressions require parameter types to be explicitly stated.
  • Treść lambda_expression może być wyrażeniem lub blokiem instrukcji, podczas gdy treść anonymous_method_expression musi być blokiem instrukcji.The body of a lambda_expression can be an expression or a statement block whereas the body of an anonymous_method_expression must be a statement block.
  • Tylko lambda_expressions mają konwersje na zgodne typy drzewa wyrażeń (Typy drzewa wyrażeń).Only lambda_expressions have conversions to compatible expression tree types (Expression tree types).

Sygnatury funkcji anonimowychAnonymous function signatures

Opcjonalna anonymous_function_signature funkcji anonimowej definiuje nazwy i opcjonalnie typy parametrów formalnych dla funkcji anonimowej.The optional anonymous_function_signature of an anonymous function defines the names and optionally the types of the formal parameters for the anonymous function. Zakresem parametrów funkcji anonimowej jest anonymous_function_body.The scope of the parameters of the anonymous function is the anonymous_function_body. (Zakresy) Wraz z listą parametrów (jeśli jest to określone), Metoda anonimowa (Deklaracja) stanowiprzestrzeń deklaracji.(Scopes) Together with the parameter list (if given) the anonymous-method-body constitutes a declaration space (Declarations). Jest to błąd czasu kompilacji dla nazwy parametru funkcji anonimowej, aby dopasować nazwę zmiennej lokalnej, stałej lokalnej lub parametru, którego zakres zawiera anonymous_method_expression lub lambda_expression.It is thus a compile-time error for the name of a parameter of the anonymous function to match the name of a local variable, local constant or parameter whose scope includes the anonymous_method_expression or lambda_expression.

Jeśli funkcja anonimowa ma explicit_anonymous_function_signature, zestaw zgodnych typów delegatów i typów drzewa wyrażeń jest ograniczony do tych, które mają te same typy parametrów i Modyfikatory w tej samej kolejności.If an anonymous function has an explicit_anonymous_function_signature, then the set of compatible delegate types and expression tree types is restricted to those that have the same parameter types and modifiers in the same order. W przeciwieństwie do konwersji grup metod (konwersje grup metod), antywariancja typów parametrów funkcji anonimowych nie jest obsługiwana.In contrast to method group conversions (Method group conversions), contra-variance of anonymous function parameter types is not supported. Jeśli funkcja anonimowa nie ma anonymous_function_signature, zestaw zgodnych typów delegatów i typów drzewa wyrażeń jest ograniczony do tych, które nie mają out parametrów.If an anonymous function does not have an anonymous_function_signature, then the set of compatible delegate types and expression tree types is restricted to those that have no out parameters.

Należy zauważyć, że anonymous_function_signature nie może zawierać atrybutów ani tablicy parametrów.Note that an anonymous_function_signature cannot include attributes or a parameter array. Niemniej jednak anonymous_function_signature może być zgodny z typem delegata, którego lista parametrów zawiera tablicę parametrów.Nevertheless, an anonymous_function_signature may be compatible with a delegate type whose parameter list contains a parameter array.

Należy również pamiętać, że konwersja na typ drzewa wyrażenia, nawet jeśli jest zgodna, może nadal kończyć się niepowodzeniem w czasie kompilacji (Typy drzewa wyrażeń).Note also that conversion to an expression tree type, even if compatible, may still fail at compile-time (Expression tree types).

Anonimowe treści funkcjiAnonymous function bodies

Treść (wyrażenie lub blok) funkcji anonimowej podlega następującym zasadom:The body (expression or block) of an anonymous function is subject to the following rules:

  • Jeśli funkcja anonimowa zawiera podpis, parametry określone w podpisie są dostępne w treści.If the anonymous function includes a signature, the parameters specified in the signature are available in the body. Jeśli funkcja anonimowa nie ma podpisu, można ją przekonwertować na typ delegata lub typ wyrażenia z parametrami (konwersje funkcji anonimowych), ale w treści nie można uzyskać dostępu do parametrów.If the anonymous function has no signature it can be converted to a delegate type or expression type having parameters (Anonymous function conversions), but the parameters cannot be accessed in the body.
  • Z wyjątkiem ref lub out parametrów określonych w sygnaturze (jeśli istnieją) najbliższej otaczającej funkcji anonimowej, jest to błąd czasu kompilacji dla treści, aby uzyskać dostęp do parametru ref lub out.Except for ref or out parameters specified in the signature (if any) of the nearest enclosing anonymous function, it is a compile-time error for the body to access a ref or out parameter.
  • Gdy typ this jest typem struktury, jest to błąd czasu kompilacji dla treści w celu uzyskania dostępu this.When the type of this is a struct type, it is a compile-time error for the body to access this. Jest to prawdziwe, czy dostęp jest jawny (jak w this.x) czy niejawny (jak w x gdzie x jest elementem członkowskim struktury).This is true whether the access is explicit (as in this.x) or implicit (as in x where x is an instance member of the struct). Ta zasada po prostu uniemożliwia takiemu dostępowi i nie wpływa na to, czy wyniki wyszukiwania elementów członkowskich są elementami członkowskimi struktury.This rule simply prohibits such access and does not affect whether member lookup results in a member of the struct.
  • Treść ma dostęp do zmiennych zewnętrznych (zmiennych zewnętrznych) funkcji anonimowej.The body has access to the outer variables (Outer variables) of the anonymous function. Dostęp do zmiennej zewnętrznej będzie odwoływać się do wystąpienia zmiennej aktywnej w chwili, gdy lambda_expression lub anonymous_method_expression jest obliczana (Obliczanie wyrażeń funkcji anonimowych).Access of an outer variable will reference the instance of the variable that is active at the time the lambda_expression or anonymous_method_expression is evaluated (Evaluation of anonymous function expressions).
  • Jest to błąd czasu kompilacji dla treści, który zawiera instrukcję goto, instrukcję break lub instrukcję continue, której element docelowy znajduje się poza treścią lub w treści zawartej funkcji anonimowej.It is a compile-time error for the body to contain a goto statement, break statement, or continue statement whose target is outside the body or within the body of a contained anonymous function.
  • Instrukcja return w treści zwraca kontrolę z wywołania najbliższej otaczającej funkcji anonimowej, a nie z otaczającego elementu członkowskiego funkcji.A return statement in the body returns control from an invocation of the nearest enclosing anonymous function, not from the enclosing function member. Wyrażenie określone w instrukcji return musi być niejawnie konwertowane na typ zwracany typu delegata lub typu drzewa wyrażenia, do którego najbliższe lambda_expression lub anonymous_method_expression są konwertowane (konwersje funkcji anonimowych).An expression specified in a return statement must be implicitly convertible to the return type of the delegate type or expression tree type to which the nearest enclosing lambda_expression or anonymous_method_expression is converted (Anonymous function conversions).

Jest on jawnie nieokreślony, niezależnie od tego, czy istnieje sposób, aby wykonać blok anonimowej funkcji innej niż Ocena i wywołanie lambda_expression lub anonymous_method_expression.It is explicitly unspecified whether there is any way to execute the block of an anonymous function other than through evaluation and invocation of the lambda_expression or anonymous_method_expression. W szczególności kompilator może zdecydować się na zaimplementowanie funkcji anonimowej przez syntezowanie jednej lub więcej nazwanych metod lub typów.In particular, the compiler may choose to implement an anonymous function by synthesizing one or more named methods or types. Nazwy wszelkich takich elementów, które można wyszukiwać, muszą mieć postać zastrzeżona do użycia przez kompilator.The names of any such synthesized elements must be of a form reserved for compiler use.

Rozpoznawanie przeciążenia i funkcje anonimoweOverload resolution and anonymous functions

Funkcje anonimowe na liście argumentów uczestniczą w wnioskach o typie i przeciążeniu.Anonymous functions in an argument list participate in type inference and overload resolution. Aby uzyskać dokładne reguły, zapoznaj się z wnioskami o typie i rozpoznaniem przeciążenia .Please refer to Type inference and Overload resolution for the exact rules.

Poniższy przykład ilustruje efekt funkcji anonimowych podczas rozpoznawania przeciążenia.The following example illustrates the effect of anonymous functions on overload resolution.

class ItemList<T>: List<T>
{
    public int Sum(Func<T,int> selector) {
        int sum = 0;
        foreach (T item in this) sum += selector(item);
        return sum;
    }

    public double Sum(Func<T,double> selector) {
        double sum = 0;
        foreach (T item in this) sum += selector(item);
        return sum;
    }
}

Klasa ItemList<T> ma dwie metody Sum.The ItemList<T> class has two Sum methods. Każdy przyjmuje selector argument, który wyodrębnia wartość do sumowania z elementu listy.Each takes a selector argument, which extracts the value to sum over from a list item. Wyodrębniona wartość może być int lub double, a wynikiem podsumowania jest również int lub double.The extracted value can be either an int or a double and the resulting sum is likewise either an int or a double.

Metody Sum mogą na przykład służyć do obliczania sum z listy wierszy szczegółów w kolejności.The Sum methods could for example be used to compute sums from a list of detail lines in an order.

class Detail
{
    public int UnitCount;
    public double UnitPrice;
    ...
}

void ComputeSums() {
    ItemList<Detail> orderDetails = GetOrderDetails(...);
    int totalUnits = orderDetails.Sum(d => d.UnitCount);
    double orderTotal = orderDetails.Sum(d => d.UnitPrice * d.UnitCount);
    ...
}

W pierwszym wywołaniu orderDetails.Sumsą stosowane obie metody Sum, ponieważ funkcja anonimowa d => d. UnitCount jest zgodna zarówno z Func<Detail,int>, jak i Func<Detail,double>.In the first invocation of orderDetails.Sum, both Sum methods are applicable because the anonymous function d => d. UnitCount is compatible with both Func<Detail,int> and Func<Detail,double>. Jednak rozwiązanie przeciążenia wybiera pierwszą metodę Sum, ponieważ konwersja do Func<Detail,int> jest lepsza niż konwersja do Func<Detail,double>.However, overload resolution picks the first Sum method because the conversion to Func<Detail,int> is better than the conversion to Func<Detail,double>.

W drugim wywołaniu orderDetails.Sumstosowana jest tylko druga metoda Sum, ponieważ funkcja anonimowa d => d.UnitPrice * d.UnitCount generuje wartość typu double.In the second invocation of orderDetails.Sum, only the second Sum method is applicable because the anonymous function d => d.UnitPrice * d.UnitCount produces a value of type double. W rezultacie rozwiązanie przeciążenia wybiera drugą metodę Sum dla tego wywołania.Thus, overload resolution picks the second Sum method for that invocation.

Funkcje anonimowe i powiązanie dynamiczneAnonymous functions and dynamic binding

Funkcja anonimowa nie może być odbiorcą, argumentem lub argumentem operacji z dynamiczną operacją.An anonymous function cannot be a receiver, argument or operand of a dynamically bound operation.

Zmienne zewnętrzneOuter variables

Każda zmienna lokalna, parametr wartości lub tablica parametrów, której zakres zawiera lambda_expression lub anonymous_method_expression jest nazywana zewnętrzną zmienną funkcji anonimowej.Any local variable, value parameter, or parameter array whose scope includes the lambda_expression or anonymous_method_expression is called an outer variable of the anonymous function. W składowej funkcji wystąpienia klasy this wartość jest uznawana za parametr wartości i jest zewnętrzną zmienną każdej funkcji anonimowej zawartej w składowej funkcji.In an instance function member of a class, the this value is considered a value parameter and is an outer variable of any anonymous function contained within the function member.

Przechwycone zmienne zewnętrzneCaptured outer variables

Gdy do zmiennej zewnętrznej odwołuje się funkcja anonimowa, zmienna zewnętrzna jest określana jako przechwycona przez funkcję anonimową.When an outer variable is referenced by an anonymous function, the outer variable is said to have been captured by the anonymous function. Zwykle okres istnienia zmiennej lokalnej jest ograniczony do wykonywania bloku lub instrukcji, z którą jest skojarzony (zmienne lokalne).Ordinarily, the lifetime of a local variable is limited to execution of the block or statement with which it is associated (Local variables). Jednak okres istnienia przechwyconej zmiennej zewnętrznej jest rozszerzany co najmniej do momentu, aż obiekt delegowany lub drzewo wyrażenia utworzone za pomocą funkcji anonimowej staną się uprawnione do wyrzucania elementów bezużytecznych.However, the lifetime of a captured outer variable is extended at least until the delegate or expression tree created from the anonymous function becomes eligible for garbage collection.

w przykładzieIn the example

using System;

delegate int D();

class Test
{
    static D F() {
        int x = 0;
        D result = () => ++x;
        return result;
    }

    static void Main() {
        D d = F();
        Console.WriteLine(d());
        Console.WriteLine(d());
        Console.WriteLine(d());
    }
}

Zmienna lokalna x jest przechwytywana przez funkcję anonimową, a okres istnienia x jest rozszerzany co najmniej do momentu, aż obiekt delegowany zwrócony przez F będzie uprawniony do wyrzucania elementów bezużytecznych (które nie są wykonywane do momentu zakończenia tego programu).the local variable x is captured by the anonymous function, and the lifetime of x is extended at least until the delegate returned from F becomes eligible for garbage collection (which doesn't happen until the very end of the program). Ponieważ każde wywołanie funkcji anonimowej działa w tym samym wystąpieniu x, dane wyjściowe tego przykładu to:Since each invocation of the anonymous function operates on the same instance of x, the output of the example is:

1
2
3

Gdy zmienna lokalna lub parametr wartości jest przechwytywany przez funkcję anonimową, zmienna lub parametr lokalny nie jest już traktowany jako zmienna stała (zmienne stałe i ruchome), ale zamiast tego jest traktowana jako ruchoma zmienna.When a local variable or a value parameter is captured by an anonymous function, the local variable or parameter is no longer considered to be a fixed variable (Fixed and moveable variables), but is instead considered to be a moveable variable. W ten sposób każdy kod unsafe, który pobiera adres przechwyconej zmiennej zewnętrznej, musi najpierw użyć instrukcji fixed, aby naprawić zmienną.Thus any unsafe code that takes the address of a captured outer variable must first use the fixed statement to fix the variable.

Należy pamiętać, że w przeciwieństwie do zmiennej nieprzechwyconej, przechwycona zmienna lokalna może być jednocześnie narażona na wiele wątków wykonywania.Note that unlike an uncaptured variable, a captured local variable can be simultaneously exposed to multiple threads of execution.

Tworzenie wystąpienia zmiennych lokalnychInstantiation of local variables

Zmienna lokalna jest uznawana za wystąpienie , gdy wykonanie wejdzie w zakres zmiennej.A local variable is considered to be instantiated when execution enters the scope of the variable. Na przykład po wywołaniu następującej metody zmienna lokalna x jest tworzona i inicjowana trzy razy — raz dla każdej iteracji pętli.For example, when the following method is invoked, the local variable x is instantiated and initialized three times—once for each iteration of the loop.

static void F() {
    for (int i = 0; i < 3; i++) {
        int x = i * 2 + 1;
        ...
    }
}

Jednak przeniesienie deklaracji x poza pętlą powoduje utworzenie pojedynczego wystąpienia x:However, moving the declaration of x outside the loop results in a single instantiation of x:

static void F() {
    int x;
    for (int i = 0; i < 3; i++) {
        x = i * 2 + 1;
        ...
    }
}

Gdy nie przechwycono, nie ma możliwości dokładnego zaobserwowania, jak często jest tworzona zmienna lokalna — ponieważ okresy istnienia wystąpień są rozłączane, istnieje możliwość, że każde wystąpienie będzie używać tej samej lokalizacji magazynu.When not captured, there is no way to observe exactly how often a local variable is instantiated—because the lifetimes of the instantiations are disjoint, it is possible for each instantiation to simply use the same storage location. Jednak gdy funkcja anonimowa przechwytuje zmienną lokalną, efekty tworzenia wystąpienia stają się oczywiste.However, when an anonymous function captures a local variable, the effects of instantiation become apparent.

PrzykładThe example

using System;

delegate void D();

class Test
{
    static D[] F() {
        D[] result = new D[3];
        for (int i = 0; i < 3; i++) {
            int x = i * 2 + 1;
            result[i] = () => { Console.WriteLine(x); };
        }
        return result;
    }

    static void Main() {
        foreach (D d in F()) d();
    }
}

tworzy dane wyjściowe:produces the output:

1
3
5

Jednakże gdy deklaracja x jest przenoszona poza pętlę:However, when the declaration of x is moved outside the loop:

static D[] F() {
    D[] result = new D[3];
    int x;
    for (int i = 0; i < 3; i++) {
        x = i * 2 + 1;
        result[i] = () => { Console.WriteLine(x); };
    }
    return result;
}

Dane wyjściowe:the output is:

5
5
5

Jeśli pętla for deklaruje zmienną iteracji, ta zmienna jest uważana za zadeklarowaną poza pętlą.If a for-loop declares an iteration variable, that variable itself is considered to be declared outside of the loop. W tym przypadku, jeśli przykład zostanie zmieniony w celu przechwycenia samej zmiennej iteracji:Thus, if the example is changed to capture the iteration variable itself:

static D[] F() {
    D[] result = new D[3];
    for (int i = 0; i < 3; i++) {
        result[i] = () => { Console.WriteLine(i); };
    }
    return result;
}

przechwytywane jest tylko jedno wystąpienie zmiennej iteracji, co daje wynik:only one instance of the iteration variable is captured, which produces the output:

3
3
3

Istnieje możliwość, że Delegaty funkcji anonimowych do udostępniania niektórych przechwyconych zmiennych jeszcze mają osobne wystąpienia innych.It is possible for anonymous function delegates to share some captured variables yet have separate instances of others. Na przykład jeśli F zostanie zmieniony naFor example, if F is changed to

static D[] F() {
    D[] result = new D[3];
    int x = 0;
    for (int i = 0; i < 3; i++) {
        int y = 0;
        result[i] = () => { Console.WriteLine("{0} {1}", ++x, ++y); };
    }
    return result;
}

trzy Delegaty przechwytują to samo wystąpienie x, ale osobne wystąpienia y, a dane wyjściowe to:the three delegates capture the same instance of x but separate instances of y, and the output is:

1 1
2 1
3 1

Oddzielne funkcje anonimowe mogą przechwytywać to samo wystąpienie zmiennej zewnętrznej.Separate anonymous functions can capture the same instance of an outer variable. W przykładzie:In the example:

using System;

delegate void Setter(int value);

delegate int Getter();

class Test
{
    static void Main() {
        int x = 0;
        Setter s = (int value) => { x = value; };
        Getter g = () => { return x; };
        s(5);
        Console.WriteLine(g());
        s(10);
        Console.WriteLine(g());
    }
}

dwie funkcje anonimowe przechwytują to samo wystąpienie zmiennej lokalnej xi w ten sposób mogą "komunikować się" za pomocą tej zmiennej.the two anonymous functions capture the same instance of the local variable x, and they can thus "communicate" through that variable. Dane wyjściowe przykładu to:The output of the example is:

5
10

Obliczanie wyrażeń funkcji anonimowychEvaluation of anonymous function expressions

Funkcja anonimowa F musi być zawsze konwertowana na typ delegata D lub typ drzewa wyrażenia Ebezpośrednio lub przez wykonanie wyrażenia tworzenia delegata new D(F).An anonymous function F must always be converted to a delegate type D or an expression tree type E, either directly or through the execution of a delegate creation expression new D(F). Ta konwersja określa wynik funkcji anonimowej, zgodnie z opisem w konwersji funkcji anonimowych.This conversion determines the result of the anonymous function, as described in Anonymous function conversions.

Wyrażenia zapytańQuery expressions

Wyrażenia zapytania zapewniają składnię języka zintegrowanego dla zapytań, które są podobne do relacyjnych i hierarchicznych języków zapytań, takich jak SQL i XQuery.Query expressions provide a language integrated syntax for queries that is similar to relational and hierarchical query languages such as SQL and XQuery.

query_expression
    : from_clause query_body
    ;

from_clause
    : 'from' type? identifier 'in' expression
    ;

query_body
    : query_body_clauses? select_or_group_clause query_continuation?
    ;

query_body_clauses
    : query_body_clause
    | query_body_clauses query_body_clause
    ;

query_body_clause
    : from_clause
    | let_clause
    | where_clause
    | join_clause
    | join_into_clause
    | orderby_clause
    ;

let_clause
    : 'let' identifier '=' expression
    ;

where_clause
    : 'where' boolean_expression
    ;

join_clause
    : 'join' type? identifier 'in' expression 'on' expression 'equals' expression
    ;

join_into_clause
    : 'join' type? identifier 'in' expression 'on' expression 'equals' expression 'into' identifier
    ;

orderby_clause
    : 'orderby' orderings
    ;

orderings
    : ordering (',' ordering)*
    ;

ordering
    : expression ordering_direction?
    ;

ordering_direction
    : 'ascending'
    | 'descending'
    ;

select_or_group_clause
    : select_clause
    | group_clause
    ;

select_clause
    : 'select' expression
    ;

group_clause
    : 'group' expression 'by' expression
    ;

query_continuation
    : 'into' identifier query_body
    ;

Wyrażenie zapytania rozpoczyna się od klauzuli from i kończyć się klauzulą select lub group.A query expression begins with a from clause and ends with either a select or group clause. Po klauzuli początkowej from może następować zero lub więcej from, let, where, join lub orderby klauzule.The initial from clause can be followed by zero or more from, let, where, join or orderby clauses. Każda klauzula from jest generatorem wprowadzającym zmienną zakresu , która przekracza elementy sekwencji.Each from clause is a generator introducing a range variable which ranges over the elements of a sequence. Każda klauzula let wprowadza zmienną zakresu reprezentującą wartość obliczoną przy użyciu wartości z poprzednich zmiennych zakresu.Each let clause introduces a range variable representing a value computed by means of previous range variables. Każda klauzula where jest filtrem, który wyklucza elementy z wyniku.Each where clause is a filter that excludes items from the result. Każda klauzula join porównuje określone klucze sekwencji źródłowej z kluczami innej sekwencji, które dają pasujące pary.Each join clause compares specified keys of the source sequence with keys of another sequence, yielding matching pairs. Każda klauzula orderby zmienia kolejność elementów zgodnie z określonymi kryteriami. Ostateczna klauzula select lub group określa kształt wyniku w zakresie zmiennych zakresu.Each orderby clause reorders items according to specified criteria.The final select or group clause specifies the shape of the result in terms of the range variables. Na koniec klauzula into może służyć do "łączenia" zapytań, traktując wyniki jednego zapytania jako generatora w kolejnych zapytaniach.Finally, an into clause can be used to "splice" queries by treating the results of one query as a generator in a subsequent query.

Niejasności w wyrażeniach zapytaniaAmbiguities in query expressions

Wyrażenia zapytań zawierają wiele "kontekstowych słów kluczowych", tj. identyfikatorów, które mają specjalne znaczenie w danym kontekście.Query expressions contain a number of "contextual keywords", i.e., identifiers that have special meaning in a given context. Są to from, where, join, on, equals, into, let, orderby, ascending, descending, select, group i by.Specifically these are from, where, join, on, equals, into, let, orderby, ascending, descending, select, group and by. Aby uniknąć niejasności w wyrażeniach zapytań spowodowanych mieszanym użyciem tych identyfikatorów jako słowa kluczowe lub nazw prostych, te identyfikatory są uznawane za słowa kluczowe w dowolnym miejscu w wyrażeniu zapytania.In order to avoid ambiguities in query expressions caused by mixed use of these identifiers as keywords or simple names, these identifiers are considered keywords when occurring anywhere within a query expression.

W tym celu wyrażenie zapytania jest dowolnym wyrażeniem rozpoczynającym się od "from identifier", po którym następuje dowolny token z wyjątkiem ";", "=" lub ",".For this purpose, a query expression is any expression that starts with "from identifier" followed by any token except ";", "=" or ",".

Aby użyć tych słów jako identyfikatorów w wyrażeniu zapytania, mogą one być poprzedzone prefiksem "@" (identyfikatorami).In order to use these words as identifiers within a query expression, they can be prefixed with "@" (Identifiers).

Tłumaczenie wyrażenia zapytaniaQuery expression translation

C# Język nie określa semantyki wykonywania wyrażeń zapytań.The C# language does not specify the execution semantics of query expressions. Zamiast tego wyrażenia zapytania są tłumaczone na wywołania metod, które są zgodne z wzorcem wyrażenia zapytania (wzorzec wyrażenia zapytania).Rather, query expressions are translated into invocations of methods that adhere to the query expression pattern (The query expression pattern). W odróżnieniu od tego wyrażenia zapytania są tłumaczone na wywołania metod o nazwach Where, Select, SelectMany, Join, GroupJoin, OrderBy, OrderByDescending, ThenBy, ThenByDescending, GroupByi Cast. Te metody powinny mieć określone sygnatury i typy wyników, zgodnie z opisem w wzorcu wyrażenia zapytania.Specifically, query expressions are translated into invocations of methods named Where, Select, SelectMany, Join, GroupJoin, OrderBy, OrderByDescending, ThenBy, ThenByDescending, GroupBy, and Cast.These methods are expected to have particular signatures and result types, as described in The query expression pattern. Metody te mogą być wystąpieniem metod obiektu, które są badane lub metod rozszerzających, które są zewnętrzne względem obiektu i implementują rzeczywiste wykonanie zapytania.These methods can be instance methods of the object being queried or extension methods that are external to the object, and they implement the actual execution of the query.

Tłumaczenie z wyrażeń zapytania do wywołania metody jest mapowaniem składni, które występuje przed wykonaniem dowolnego powiązania typu lub Rozpoznanie przeciążenia.The translation from query expressions to method invocations is a syntactic mapping that occurs before any type binding or overload resolution has been performed. Tłumaczenie jest gwarantowane pod kątem poprawności składniowej, ale nie gwarantuje, że jest to bardziej prawidłowy C# kod.The translation is guaranteed to be syntactically correct, but it is not guaranteed to produce semantically correct C# code. Po translacji wyrażeń zapytania wyniki wywoływanych metod są przetwarzane jako zwykłe wywołania metod i może to spowodować błędy odkrywania, na przykład jeśli metody nie istnieją, jeśli argumenty mają nieprawidłowe typy lub jeśli metody są ogólne i Wnioskowanie o typie nie powiodło się.Following translation of query expressions, the resulting method invocations are processed as regular method invocations, and this may in turn uncover errors, for example if the methods do not exist, if arguments have wrong types, or if the methods are generic and type inference fails.

Wyrażenie zapytania jest przetwarzane przez wielokrotne zastosowanie następujących tłumaczeń, dopóki nie będzie możliwe dalsze zmniejszenie.A query expression is processed by repeatedly applying the following translations until no further reductions are possible. Tłumaczenia są wymienione w kolejności aplikacji: w każdej sekcji przyjęto założenie, że tłumaczenia w powyższych sekcjach zostały wykonane wyczerpująco, a po wyczerpaniu sekcja nie będzie później oglądany w przetwarzaniu tego samego wyrażenia zapytania.The translations are listed in order of application: each section assumes that the translations in the preceding sections have been performed exhaustively, and once exhausted, a section will not later be revisited in the processing of the same query expression.

Przypisanie do zmiennych zakresu nie jest dozwolone w wyrażeniach zapytań.Assignment to range variables is not allowed in query expressions. Jednakże C# implementacja może nie zawsze wymuszać tego ograniczenia, ponieważ czasami nie jest to możliwe przy użyciu schematu tłumaczenia składni przedstawionego w tym miejscu.However a C# implementation is permitted to not always enforce this restriction, since this may sometimes not be possible with the syntactic translation scheme presented here.

Niektóre tłumaczenia wprowadzają zmienne zakresów z przezroczystymi identyfikatorami wskazywanymi przez *.Certain translations inject range variables with transparent identifiers denoted by *. Specjalne właściwości przezroczystych identyfikatorów są omówione bardziej szczegółowo w przezroczystych identyfikatorach.The special properties of transparent identifiers are discussed further in Transparent identifiers.

Klauzule SELECT i GroupBy z kontynuacjamiSelect and groupby clauses with continuations

Wyrażenie zapytania z kontynuacjąA query expression with a continuation

from ... into x ...

jest przetłumaczony nais translated into

from x in ( from ... ) ...

W przypadku tłumaczeń w poniższych sekcjach przyjęto założenie, że zapytania nie mają kontynuacji into.The translations in the following sections assume that queries have no into continuations.

PrzykładThe example

from c in customers
group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() }

jest przetłumaczony nais translated into

from g in
    from c in customers
    group c by c.Country
select new { Country = g.Key, CustCount = g.Count() }

końcowe tłumaczenie tothe final translation of which is

customers.
GroupBy(c => c.Country).
Select(g => new { Country = g.Key, CustCount = g.Count() })

Jawne typy zmiennych zakresuExplicit range variable types

Klauzula from, która jawnie określa typ zmiennej zakresuA from clause that explicitly specifies a range variable type

from T x in e

jest przetłumaczony nais translated into

from x in ( e ) . Cast < T > ( )

Klauzula join, która jawnie określa typ zmiennej zakresuA join clause that explicitly specifies a range variable type

join T x in e on k1 equals k2

jest przetłumaczony nais translated into

join x in ( e ) . Cast < T > ( ) on k1 equals k2

W przypadku tłumaczeń w poniższych sekcjach przyjęto założenie, że zapytania nie mają jawnych typów zmiennych zakresu.The translations in the following sections assume that queries have no explicit range variable types.

PrzykładThe example

from Customer c in customers
where c.City == "London"
select c

jest przetłumaczony nais translated into

from c in customers.Cast<Customer>()
where c.City == "London"
select c

końcowe tłumaczenie tothe final translation of which is

customers.
Cast<Customer>().
Where(c => c.City == "London")

Jawne typy zmiennych zakresu są przydatne do wykonywania zapytań dotyczących kolekcji implementujących nieogólny interfejs IEnumerable, ale nie do ogólnego interfejsu IEnumerable<T>.Explicit range variable types are useful for querying collections that implement the non-generic IEnumerable interface, but not the generic IEnumerable<T> interface. W powyższym przykładzie jest to przypadek, jeśli customers były typu ArrayList.In the example above, this would be the case if customers were of type ArrayList.

Wygeneruj wyrażenia zapytaniaDegenerate query expressions

Wyrażenie zapytania w formularzuA query expression of the form

from x in e select x

jest przetłumaczony nais translated into

( e ) . Select ( x => x )

PrzykładThe example

from c in customers
select c

jest przetłumaczony nais translated into

customers.Select(c => c)

Wygeneruj wyrażenie zapytania, które w sposób nieprosty wybiera elementy źródła.A degenerate query expression is one that trivially selects the elements of the source. Późniejsza faza tłumaczenia powoduje usunięcie niegenerowanych zapytań, które zostały wprowadzone przez inne etapy tłumaczenia, zastępując je ich źródłem.A later phase of the translation removes degenerate queries introduced by other translation steps by replacing them with their source. Ważne jest jednak, aby upewnić się, że wynik wyrażenia zapytania nigdy nie jest obiektem źródłowym, co spowoduje ujawnienie typu i tożsamości źródła do klienta zapytania.It is important however to ensure that the result of a query expression is never the source object itself, as that would reveal the type and identity of the source to the client of the query. W związku z tym ten krok chroni wygenerowanie zapytań pisanych bezpośrednio w kodzie źródłowym przez jawne wywołanie Select na źródle.Therefore this step protects degenerate queries written directly in source code by explicitly calling Select on the source. Następnie do realizatorów Select i innych operatorów zapytań, aby upewnić się, że te metody nigdy nie zwracają samego obiektu źródłowego.It is then up to the implementers of Select and other query operators to ensure that these methods never return the source object itself.

Klauzule from, let, WHERE, join i OrderByFrom, let, where, join and orderby clauses

Wyrażenie zapytania z drugą klauzulą from, po którym następuje klauzula selectA query expression with a second from clause followed by a select clause

from x1 in e1
from x2 in e2
select v

jest przetłumaczony nais translated into

( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => v )

Wyrażenie zapytania z drugą klauzulą from, po którym następuje coś innego niż klauzula select:A query expression with a second from clause followed by something other than a select clause:

from x1 in e1
from x2 in e2
...

jest przetłumaczony nais translated into

from * in ( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => new { x1 , x2 } )
...

Wyrażenie zapytania z klauzulą letA query expression with a let clause

from x in e
let y = f
...

jest przetłumaczony nais translated into

from * in ( e ) . Select ( x => new { x , y = f } )
...

Wyrażenie zapytania z klauzulą whereA query expression with a where clause

from x in e
where f
...

jest przetłumaczony nais translated into

from x in ( e ) . Where ( x => f )
...

Wyrażenie zapytania z klauzulą join bez into, po którym następuje klauzula selectA query expression with a join clause without an into followed by a select clause

from x1 in e1
join x2 in e2 on k1 equals k2
select v

jest przetłumaczony nais translated into

( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => v )

Wyrażenie zapytania z klauzulą join bez into, po którym następuje element inny niż klauzula selectA query expression with a join clause without an into followed by something other than a select clause

from x1 in e1
join x2 in e2 on k1 equals k2
...

jest przetłumaczony nais translated into

from * in ( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => new { x1 , x2 })
...

Wyrażenie zapytania z klauzulą join z into po którym następuje klauzula selectA query expression with a join clause with an into followed by a select clause

from x1 in e1
join x2 in e2 on k1 equals k2 into g
select v

jest przetłumaczony nais translated into

( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => v )

Wyrażenie zapytania z klauzulą join zawierającą into, a następnie element inny niż klauzula selectA query expression with a join clause with an into followed by something other than a select clause

from x1 in e1
join x2 in e2 on k1 equals k2 into g
...

jest przetłumaczony nais translated into

from * in ( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => new { x1 , g })
...

Wyrażenie zapytania z klauzulą orderbyA query expression with an orderby clause

from x in e
orderby k1 , k2 , ..., kn
...

jest przetłumaczony nais translated into

from x in ( e ) . 
OrderBy ( x => k1 ) . 
ThenBy ( x => k2 ) .
... .
ThenBy ( x => kn )
...

Jeśli klauzula porządkowania określa descending wskaźnik kierunku, zamiast tego zostanie utworzone wywołanie OrderByDescending lub ThenByDescending.If an ordering clause specifies a descending direction indicator, an invocation of OrderByDescending or ThenByDescending is produced instead.

Poniższe tłumaczenia zakładają, że nie istnieją klauzule let, where, join lub orderby i nie więcej niż jedna początkowa klauzula from w każdym wyrażeniu zapytania.The following translations assume that there are no let, where, join or orderby clauses, and no more than the one initial from clause in each query expression.

PrzykładThe example

from c in customers
from o in c.Orders
select new { c.Name, o.OrderID, o.Total }

jest przetłumaczony nais translated into

customers.
SelectMany(c => c.Orders,
     (c,o) => new { c.Name, o.OrderID, o.Total }
)

PrzykładThe example

from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }

jest przetłumaczony nais translated into

from * in customers.
    SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }

końcowe tłumaczenie tothe final translation of which is

customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(x => x.o.Total).
Select(x => new { x.c.Name, x.o.OrderID, x.o.Total })

gdzie x to identyfikator wygenerowany przez kompilator, który jest w przeciwnym razie niewidoczny i niedostępny.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

PrzykładThe example

from o in orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
where t >= 1000
select new { o.OrderID, Total = t }

jest przetłumaczony nais translated into

from * in orders.
    Select(o => new { o, t = o.Details.Sum(d => d.UnitPrice * d.Quantity) })
where t >= 1000 
select new { o.OrderID, Total = t }

końcowe tłumaczenie tothe final translation of which is

orders.
Select(o => new { o, t = o.Details.Sum(d => d.UnitPrice * d.Quantity) }).
Where(x => x.t >= 1000).
Select(x => new { x.o.OrderID, Total = x.t })

gdzie x to identyfikator wygenerowany przez kompilator, który jest w przeciwnym razie niewidoczny i niedostępny.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

PrzykładThe example

from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total }

jest przetłumaczony nais translated into

customers.Join(orders, c => c.CustomerID, o => o.CustomerID,
    (c, o) => new { c.Name, o.OrderDate, o.Total })

PrzykładThe example

from c in customers
join o in orders on c.CustomerID equals o.CustomerID into co
let n = co.Count()
where n >= 10
select new { c.Name, OrderCount = n }

jest przetłumaczony nais translated into

from * in customers.
    GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,
        (c, co) => new { c, co })
let n = co.Count()
where n >= 10 
select new { c.Name, OrderCount = n }

końcowe tłumaczenie tothe final translation of which is

customers.
GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,
    (c, co) => new { c, co }).
Select(x => new { x, n = x.co.Count() }).
Where(y => y.n >= 10).
Select(y => new { y.x.c.Name, OrderCount = y.n)

gdzie x i y są wygenerowanymi przez kompilator identyfikatorami, które w przeciwnym razie są niewidoczne i niedostępne.where x and y are compiler generated identifiers that are otherwise invisible and inaccessible.

PrzykładThe example

from o in orders
orderby o.Customer.Name, o.Total descending
select o

ma końcowe tłumaczeniehas the final translation

orders.
OrderBy(o => o.Customer.Name).
ThenByDescending(o => o.Total)

Wybierz klauzuleSelect clauses

Wyrażenie zapytania w formularzuA query expression of the form

from x in e select v

jest przetłumaczony nais translated into

( e ) . Select ( x => v )

z wyjątkiem sytuacji, gdy v jest identyfikatorem x, tłumaczenie jest po prostuexcept when v is the identifier x, the translation is simply

( e )

Na przykład:For example

from c in customers.Where(c => c.City == "London")
select c

jest po prostu przetłumaczony nais simply translated into

customers.Where(c => c.City == "London")

Klauzule GroupByGroupby clauses

Wyrażenie zapytania w formularzuA query expression of the form

from x in e group v by k

jest przetłumaczony nais translated into

( e ) . GroupBy ( x => k , x => v )

z wyjątkiem sytuacji, gdy v jest identyfikatorem x, tłumaczenie jestexcept when v is the identifier x, the translation is

( e ) . GroupBy ( x => k )

PrzykładThe example

from c in customers
group c.Name by c.Country

jest przetłumaczony nais translated into

customers.
GroupBy(c => c.Country, c => c.Name)

Identyfikatory przezroczysteTransparent identifiers

Niektóre tłumaczenia wprowadzają zmienne zakresów z przezroczystymi identyfikatorami wskazywanymi przez *.Certain translations inject range variables with transparent identifiers denoted by *. Przezroczyste identyfikatory nie są właściwą funkcją języka; istnieją one tylko jako pośredni krok w procesie tłumaczenia wyrażenia zapytania.Transparent identifiers are not a proper language feature; they exist only as an intermediate step in the query expression translation process.

Gdy tłumaczenie zapytania powoduje iniekcję przezroczystego identyfikatora, dalsze etapy tłumaczenia propagują przezroczysty identyfikator do funkcji anonimowych i inicjatorów obiektów anonimowych.When a query translation injects a transparent identifier, further translation steps propagate the transparent identifier into anonymous functions and anonymous object initializers. W tych kontekstach przezroczyste identyfikatory mają następujące zachowanie:In those contexts, transparent identifiers have the following behavior:

  • Gdy przezroczysty identyfikator występuje jako parametr w funkcji anonimowej, elementy członkowskie skojarzonego typu anonimowego są automatycznie w zakresie w treści funkcji anonimowej.When a transparent identifier occurs as a parameter in an anonymous function, the members of the associated anonymous type are automatically in scope in the body of the anonymous function.
  • Gdy członek z przezroczystym identyfikatorem znajduje się w zakresie, członkowie tego elementu członkowskiego są również w zakresie.When a member with a transparent identifier is in scope, the members of that member are in scope as well.
  • Gdy przezroczysty identyfikator występuje jako element członkowski deklarator w inicjatorze obiektu anonimowego, wprowadza element członkowski z przezroczystym identyfikatorem.When a transparent identifier occurs as a member declarator in an anonymous object initializer, it introduces a member with a transparent identifier.
  • W opisanych powyżej krokach, przezroczyste identyfikatory są zawsze wprowadzane wraz z typami anonimowymi, z zamiarem przechwytywania wielu zmiennych zakresu jako elementów członkowskich jednego obiektu.In the translation steps described above, transparent identifiers are always introduced together with anonymous types, with the intent of capturing multiple range variables as members of a single object. Implementacja programu C# może korzystać z innego mechanizmu niż typy anonimowe, aby grupować jednocześnie wiele zmiennych zakresu.An implementation of C# is permitted to use a different mechanism than anonymous types to group together multiple range variables. Poniższe przykłady translacji założono, że są używane typy anonimowe i pokazują, jak przezroczyste identyfikatory mogą być przetłumaczone.The following translation examples assume that anonymous types are used, and show how transparent identifiers can be translated away.

PrzykładThe example

from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.Total }

jest przetłumaczony nais translated into

from * in customers.
    SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.Total }

który jest bardziej przetłumaczony nawhich is further translated into

customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(* => o.Total).
Select(* => new { c.Name, o.Total })

które po wymazaniu przezroczystych identyfikatorów są równoważnewhich, when transparent identifiers are erased, is equivalent to

customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(x => x.o.Total).
Select(x => new { x.c.Name, x.o.Total })

gdzie x to identyfikator wygenerowany przez kompilator, który jest w przeciwnym razie niewidoczny i niedostępny.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

PrzykładThe example

from c in customers
join o in orders on c.CustomerID equals o.CustomerID
join d in details on o.OrderID equals d.OrderID
join p in products on d.ProductID equals p.ProductID
select new { c.Name, o.OrderDate, p.ProductName }

jest przetłumaczony nais translated into

from * in customers.
    Join(orders, c => c.CustomerID, o => o.CustomerID, 
        (c, o) => new { c, o })
join d in details on o.OrderID equals d.OrderID
join p in products on d.ProductID equals p.ProductID
select new { c.Name, o.OrderDate, p.ProductName }

który jest bardziej skrócony dowhich is further reduced to

customers.
Join(orders, c => c.CustomerID, o => o.CustomerID, (c, o) => new { c, o }).
Join(details, * => o.OrderID, d => d.OrderID, (*, d) => new { *, d }).
Join(products, * => d.ProductID, p => p.ProductID, (*, p) => new { *, p }).
Select(* => new { c.Name, o.OrderDate, p.ProductName })

końcowe tłumaczenie tothe final translation of which is

customers.
Join(orders, c => c.CustomerID, o => o.CustomerID,
    (c, o) => new { c, o }).
Join(details, x => x.o.OrderID, d => d.OrderID,
    (x, d) => new { x, d }).
Join(products, y => y.d.ProductID, p => p.ProductID,
    (y, p) => new { y, p }).
Select(z => new { z.y.x.c.Name, z.y.x.o.OrderDate, z.p.ProductName })

gdzie x, yi z są wygenerowanymi przez kompilator identyfikatorami, które w przeciwnym razie są niewidoczne i niedostępne.where x, y, and z are compiler generated identifiers that are otherwise invisible and inaccessible.

Wzorzec wyrażenia zapytaniaThe query expression pattern

Wzorzec wyrażenia zapytania stanowi wzorzec metod, które typy mogą zaimplementować do obsługi wyrażeń zapytań.The Query expression pattern establishes a pattern of methods that types can implement to support query expressions. Ponieważ wyrażenia zapytania są tłumaczone na wywołania metod przy użyciu mapowania składni, typy mają znaczną elastyczność w sposobie implementowania wzorca wyrażenia zapytania.Because query expressions are translated to method invocations by means of a syntactic mapping, types have considerable flexibility in how they implement the query expression pattern. Na przykład metody wzorca mogą być implementowane jako metody instancji lub jako metody rozszerzające, ponieważ dwie mają tę samą składnię wywołania, a metody mogą zażądać delegatów lub drzew wyrażeń, ponieważ funkcje anonimowe są konwertowane do obu tych elementów.For example, the methods of the pattern can be implemented as instance methods or as extension methods because the two have the same invocation syntax, and the methods can request delegates or expression trees because anonymous functions are convertible to both.

Poniżej przedstawiono zalecany kształt typu ogólnego C<T>, który obsługuje wzorzec wyrażenia zapytania.The recommended shape of a generic type C<T> that supports the query expression pattern is shown below. Typ ogólny jest używany w celu zilustrowania właściwych relacji między parametrami i typami wyników, ale istnieje możliwość zaimplementowania wzorca dla typów innych niż ogólne.A generic type is used in order to illustrate the proper relationships between parameter and result types, but it is possible to implement the pattern for non-generic types as well.

delegate R Func<T1,R>(T1 arg1);

delegate R Func<T1,T2,R>(T1 arg1, T2 arg2);

class C
{
    public C<T> Cast<T>();
}

class C<T> : C
{
    public C<T> Where(Func<T,bool> predicate);

    public C<U> Select<U>(Func<T,U> selector);

    public C<V> SelectMany<U,V>(Func<T,C<U>> selector,
        Func<T,U,V> resultSelector);

    public C<V> Join<U,K,V>(C<U> inner, Func<T,K> outerKeySelector,
        Func<U,K> innerKeySelector, Func<T,U,V> resultSelector);

    public C<V> GroupJoin<U,K,V>(C<U> inner, Func<T,K> outerKeySelector,
        Func<U,K> innerKeySelector, Func<T,C<U>,V> resultSelector);

    public O<T> OrderBy<K>(Func<T,K> keySelector);

    public O<T> OrderByDescending<K>(Func<T,K> keySelector);

    public C<G<K,T>> GroupBy<K>(Func<T,K> keySelector);

    public C<G<K,E>> GroupBy<K,E>(Func<T,K> keySelector,
        Func<T,E> elementSelector);
}

class O<T> : C<T>
{
    public O<T> ThenBy<K>(Func<T,K> keySelector);

    public O<T> ThenByDescending<K>(Func<T,K> keySelector);
}

class G<K,T> : C<T>
{
    public K Key { get; }
}

W powyższych metodach użyto ogólnych typów delegatów Func<T1,R> i Func<T1,T2,R>, ale mogą być równie dobrze używane inne Delegaty lub typy drzewa wyrażeń z tymi samymi relacjami w typach parametrów i wyników.The methods above use the generic delegate types Func<T1,R> and Func<T1,T2,R>, but they could equally well have used other delegate or expression tree types with the same relationships in parameter and result types.

Zwróć uwagę na zalecaną relację między C<T> i O<T>, która zapewnia, że metody ThenBy i ThenByDescending są dostępne tylko w wyniku OrderBy lub OrderByDescending.Notice the recommended relationship between C<T> and O<T> which ensures that the ThenBy and ThenByDescending methods are available only on the result of an OrderBy or OrderByDescending. Zauważ również, że zalecany kształt wyniku GroupBy--sekwencji sekwencji, gdzie każda sekwencja wewnętrzna ma dodatkową właściwość Key.Also notice the recommended shape of the result of GroupBy -- a sequence of sequences, where each inner sequence has an additional Key property.

Przestrzeń nazw System.Linq zawiera implementację wzorca operatora zapytania dla dowolnego typu, który implementuje interfejs System.Collections.Generic.IEnumerable<T>.The System.Linq namespace provides an implementation of the query operator pattern for any type that implements the System.Collections.Generic.IEnumerable<T> interface.

Operatory przypisaniaAssignment operators

Operatory przypisania przypisują nową wartość do zmiennej, właściwości, zdarzenia lub elementu indeksatora.The assignment operators assign a new value to a variable, a property, an event, or an indexer element.

assignment
    : unary_expression assignment_operator expression
    ;

assignment_operator
    : '='
    | '+='
    | '-='
    | '*='
    | '/='
    | '%='
    | '&='
    | '|='
    | '^='
    | '<<='
    | right_shift_assignment
    ;

Lewy operand przypisania musi być wyrażeniem sklasyfikowanym jako zmienna, dostępem do właściwości, dostępem indeksatora lub dostępem do zdarzeń.The left operand of an assignment must be an expression classified as a variable, a property access, an indexer access, or an event access.

Operator = nosi nazwę prostego operatora przypisania.The = operator is called the simple assignment operator. Przypisuje wartość operandu Right do zmiennej, właściwości lub elementu indeksatora podaną przez lewy argument operacji.It assigns the value of the right operand to the variable, property, or indexer element given by the left operand. Lewy argument operacji prostego operatora przypisania nie może być dostępem do zdarzeń (z wyjątkiem opisanych w zdarzeniach przypominających pola).The left operand of the simple assignment operator may not be an event access (except as described in Field-like events). Prosty operator przypisania został opisany w prostym przypisaniu.The simple assignment operator is described in Simple assignment.

Operatory przypisania inne niż operator = są nazywane operatorami przypisania złożonego.The assignment operators other than the = operator are called the compound assignment operators. Te operatory wykonują wskazane operacje na dwóch operandach, a następnie przypisują wartość wyniki do zmiennej, właściwości lub elementu indeksatora podanego przez lewy operand.These operators perform the indicated operation on the two operands, and then assign the resulting value to the variable, property, or indexer element given by the left operand. Operatory przypisania złożonego są opisane w przypisaniu złożonym.The compound assignment operators are described in Compound assignment.

Operatory += i -= z wyrażeniem dostępu do zdarzenia jako lewy operand są nazywane operatorami przypisania zdarzenia.The += and -= operators with an event access expression as the left operand are called the event assignment operators. Żaden inny operator przypisania nie jest prawidłowy w przypadku dostępu do zdarzenia jako lewego operandu.No other assignment operator is valid with an event access as the left operand. Operatory przypisania zdarzeń są opisane w przypisaniu zdarzeń.The event assignment operators are described in Event assignment.

Operatory przypisania są z prawej strony skojarzenia, co oznacza, że operacje są pogrupowane od prawej do lewej.The assignment operators are right-associative, meaning that operations are grouped from right to left. Na przykład wyrażenie a = b = c jest oceniane jako a = (b = c).For example, an expression of the form a = b = c is evaluated as a = (b = c).

Przypisanie prosteSimple assignment

Operator = nosi nazwę prostego operatora przypisania.The = operator is called the simple assignment operator.

Jeśli lewy operand prostego przypisywania ma postać E.P lub E[Ei] gdzie E ma dynamictypu czasu kompilacji, przypisanie jest powiązane dynamicznie (powiązanie dynamiczne).If the left operand of a simple assignment is of the form E.P or E[Ei] where E has the compile-time type dynamic, then the assignment is dynamically bound (Dynamic binding). W takim przypadku typem czasu kompilowania w wyrażeniu przypisania jest dynamic, a rozwiązanie opisane poniżej będzie odbywać się w czasie wykonywania na podstawie typu Ew czasie wykonywania.In this case the compile-time type of the assignment expression is dynamic, and the resolution described below will take place at run-time based on the run-time type of E.

W prostym przypisaniu, prawy operand musi być wyrażeniem, które jest niejawnie konwertowane na typ operandu po lewej stronie.In a simple assignment, the right operand must be an expression that is implicitly convertible to the type of the left operand. Operacja przypisuje wartość operandu Right do zmiennej, właściwości lub elementu indeksatora podaną przez lewy argument operacji.The operation assigns the value of the right operand to the variable, property, or indexer element given by the left operand.

Wynikiem prostego wyrażenia przypisania jest wartość przypisana do lewego operandu.The result of a simple assignment expression is the value assigned to the left operand. Wynik ma ten sam typ co lewy operand i jest zawsze sklasyfikowany jako wartość.The result has the same type as the left operand and is always classified as a value.

Jeśli argument operacji po lewej stronie jest dostępną właściwością lub indeksatorem, właściwość lub indeksator musi mieć metodę dostępu set.If the left operand is a property or indexer access, the property or indexer must have a set accessor. W przeciwnym razie wystąpi błąd w czasie powiązania.If this is not the case, a binding-time error occurs.

Przetwarzanie prostego przypisania formularza x = y w czasie wykonywania obejmuje następujące kroki:The run-time processing of a simple assignment of the form x = y consists of the following steps:

  • Jeśli x jest sklasyfikowana jako zmienna:If x is classified as a variable:
    • x jest oceniane, aby utworzyć zmienną.x is evaluated to produce the variable.
    • y jest oceniane i, w razie potrzeby, konwertowane na typ x za pomocą konwersji niejawnej (konwersje niejawne).y is evaluated and, if required, converted to the type of x through an implicit conversion (Implicit conversions).
    • Jeśli zmienna określona przez x jest elementem tablicy reference_type, wykonywane jest sprawdzanie w czasie wykonywania, aby upewnić się, że wartość obliczona dla y jest zgodna z wystąpieniem tablicy, którego x jest elementem.If the variable given by x is an array element of a reference_type, a run-time check is performed to ensure that the value computed for y is compatible with the array instance of which x is an element. Sprawdzanie kończy się powodzeniem, jeśli y jest null, lub Jeśli niejawna konwersja odwołań (niejawne konwersje odwołań) istnieje z rzeczywistego typu wystąpienia, do którego odwołuje się y do rzeczywistego typu elementu wystąpienia tablicy zawierającego x.The check succeeds if y is null, or if an implicit reference conversion (Implicit reference conversions) exists from the actual type of the instance referenced by y to the actual element type of the array instance containing x. W przeciwnym razie zostanie zgłoszony System.ArrayTypeMismatchException.Otherwise, a System.ArrayTypeMismatchException is thrown.
    • Wartość będąca wynikiem oceny i konwersji y jest przechowywana w lokalizacji podawanej przez ocenę x.The value resulting from the evaluation and conversion of y is stored into the location given by the evaluation of x.
  • Jeśli x jest klasyfikowany jako dostęp do właściwości lub indeksatora:If x is classified as a property or indexer access:
    • Wyrażenie wystąpienia (jeśli x nie jest static) i lista argumentów (jeśli x jest dostępem indeksatora), które są skojarzone z x są oceniane, a wyniki są używane w kolejnym wywołaniu metody 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 set accessor invocation.
    • y jest oceniane i, w razie potrzeby, konwertowane na typ x za pomocą konwersji niejawnej (konwersje niejawne).y is evaluated and, if required, converted to the type of x through an implicit conversion (Implicit conversions).
    • Metoda dostępu set x jest wywoływana z wartością obliczaną dla y jako argument value.The set accessor of x is invoked with the value computed for y as its value argument.

Reguły współwariancji tablicy (Kowariancja tablicowa) zezwalają na wartość typu tablicy A[] być odwołaniem do wystąpienia typu tablicy B[], pod warunkiem, że istnieje niejawna konwersja odwołań z B do 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. Ze względu na te reguły przypisanie do elementu tablicy reference_type wymaga sprawdzenia w czasie wykonywania, aby upewnić się, że przypisywana wartość jest zgodna z wystąpieniem tablicy.Because of these rules, assignment to an array element of a reference_type requires a run-time check to ensure that the value being assigned is compatible with the array instance. w przykładzieIn the example

string[] sa = new string[10];
object[] oa = sa;

oa[0] = null;               // Ok
oa[1] = "Hello";            // Ok
oa[2] = new ArrayList();    // ArrayTypeMismatchException

Ostatnie przypisanie powoduje wygenerowanie System.ArrayTypeMismatchException, ponieważ wystąpienie ArrayList nie może być przechowywane w elemencie string[].the last assignment causes a System.ArrayTypeMismatchException to be thrown because an instance of ArrayList cannot be stored in an element of a string[].

Gdy właściwość lub indeksator zadeklarowany w struct_type jest elementem docelowym przypisania, wyrażenie wystąpienia skojarzone z właściwością lub dostępem indeksatora musi być sklasyfikowane jako zmienna.When a property or indexer declared in a struct_type is the target of an assignment, the instance expression associated with the property or indexer access must be classified as a variable. Jeśli wyrażenie wystąpienia jest sklasyfikowane jako wartość, wystąpi błąd w czasie powiązania.If the instance expression is classified as a value, a binding-time error occurs. Ze względu na dostęp do elementu członkowskiegota sama reguła dotyczy również pól.Because of Member access, the same rule also applies to fields.

Uwzględniając deklaracje:Given the declarations:

struct Point
{
    int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

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

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

struct Rectangle
{
    Point a, b;

    public Rectangle(Point a, Point b) {
        this.a = a;
        this.b = b;
    }

    public Point A {
        get { return a; }
        set { a = value; }
    }

    public Point B {
        get { return b; }
        set { b = value; }
    }
}

w przykładziein the example

Point p = new Point();
p.X = 100;
p.Y = 100;
Rectangle r = new Rectangle();
r.A = new Point(10, 10);
r.B = p;

przypisania do p.X, p.Y, r.Ai r.B są dozwolone, ponieważ p i r są zmiennymi.the assignments to p.X, p.Y, r.A, and r.B are permitted because p and r are variables. Jednak w przykładzieHowever, in the example

Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;

wszystkie przypisania są nieprawidłowe, ponieważ r.A i r.B nie są zmiennymi.the assignments are all invalid, since r.A and r.B are not variables.

Przypisanie złożoneCompound assignment

Jeśli argument operacji po lewej stronie przypisania złożonego ma postać E.P lub E[Ei] gdzie E ma dynamictypu czasu kompilacji, przypisanie jest powiązane dynamicznie (powiązanie dynamiczne).If the left operand of a compound assignment is of the form E.P or E[Ei] where E has the compile-time type dynamic, then the assignment is dynamically bound (Dynamic binding). W takim przypadku typem czasu kompilowania w wyrażeniu przypisania jest dynamic, a rozwiązanie opisane poniżej będzie odbywać się w czasie wykonywania na podstawie typu Ew czasie wykonywania.In this case the compile-time type of the assignment expression is dynamic, and the resolution described below will take place at run-time based on the run-time type of E.

Operacja x op= y jest przetwarzana przez zastosowanie rozpoznawania przeciążenia operatora binarnego (Rozpoznanie przeciążenia operatora binarnego), tak jakby operacja była zapisywana x op y.An operation of the form x op= y is processed by applying binary operator overload resolution (Binary operator overload resolution) as if the operation was written x op y. NastępnieThen,

  • Jeśli zwracany typ wybranego operatora jest niejawnie konwertowany na typ x, operacja zostanie oceniona jako x = x op y, z tą różnicą, że x jest oceniana tylko raz.If the return type of the selected operator is implicitly convertible to the type of x, the operation is evaluated as x = x op y, except that x is evaluated only once.
  • W przeciwnym razie, jeśli wybrany operator jest wstępnie zdefiniowanym operatorem, Jeśli zwracany typ wybranego operatora jest jawnie konwertowany na typ xi jeśli y jest niejawnie konwertowany na typ x lub operator jest operatorem przesunięcia, wówczas operacja jest szacowana jako x = (T)(x op y), gdzie T jest typem x, z wyjątkiem tego, że x jest oceniane tylko raz.Otherwise, if the selected operator is a predefined operator, if the return type of the selected operator is explicitly convertible to the type of x, and if y is implicitly convertible to the type of x or the operator is a shift operator, then the operation is evaluated as x = (T)(x op y), where T is the type of x, except that x is evaluated only once.
  • W przeciwnym razie złożone przypisanie jest nieprawidłowe i wystąpi błąd w czasie trwania powiązania.Otherwise, the compound assignment is invalid, and a binding-time error occurs.

Termin "oceniony tylko raz" oznacza, że podczas oceny x op ywyniki wszelkich wyrażeń składników x są tymczasowo zapisywane, a następnie ponownie używane podczas wykonywania przypisania do x.The term "evaluated only once" means that in the evaluation of x op y, the results of any constituent expressions of x are temporarily saved and then reused when performing the assignment to x. Na przykład w A()[B()] += C()przypisywania, gdzie A jest metodą zwracającą int[], a B i C są metodami zwracającymi int, metody są wywoływane tylko raz, w kolejności A, B, C.For example, in the assignment A()[B()] += C(), where A is a method returning int[], and B and C are methods returning int, the methods are invoked only once, in the order A, B, C.

Gdy argument operacji po lewej stronie przypisania złożonego jest dostęp do właściwości lub indeksatora, właściwość lub indeksator musi mieć zarówno metodę dostępu get, jak i metodę dostępu set.When the left operand of a compound assignment is a property access or indexer access, the property or indexer must have both a get accessor and a set accessor. W przeciwnym razie wystąpi błąd w czasie powiązania.If this is not the case, a binding-time error occurs.

Druga reguła powyżej zezwala x op= y na ocenę jako x = (T)(x op y) w określonych kontekstach.The second rule above permits x op= y to be evaluated as x = (T)(x op y) in certain contexts. Reguła istnieje tak, aby wstępnie zdefiniowane operatory mogły być używane jako operatory złożone, gdy argument operacji po lewej stronie jest typu sbyte, byte, short, ushortlub char.The rule exists such that the predefined operators can be used as compound operators when the left operand is of type sbyte, byte, short, ushort, or char. Nawet jeśli oba argumenty są jednego z tych typów, wstępnie zdefiniowane operatory generują wynik typu int, zgodnie z opisem w binarnej promocji liczbowych.Even when both arguments are of one of those types, the predefined operators produce a result of type int, as described in Binary numeric promotions. W związku z tym bez rzutowania nie można przypisać wyniku do lewego operandu.Thus, without a cast it would not be possible to assign the result to the left operand.

Intuicyjny efekt reguły dla wstępnie zdefiniowanych operatorów to po prostu, że x op= y jest dozwolony, jeśli oba x op y i x = y są dozwolone.The intuitive effect of the rule for predefined operators is simply that x op= y is permitted if both of x op y and x = y are permitted. w przykładzieIn the example

byte b = 0;
char ch = '\0';
int i = 0;

b += 1;             // Ok
b += 1000;          // Error, b = 1000 not permitted
b += i;             // Error, b = i not permitted
b += (byte)i;       // Ok

ch += 1;            // Error, ch = 1 not permitted
ch += (char)1;      // Ok

intuicyjną przyczyną każdego błędu jest to, że odpowiednie proste przypisanie mogło również być błędem.the intuitive reason for each error is that a corresponding simple assignment would also have been an error.

Oznacza to również, że operacje przypisania złożonego obsługują podniesione operacje.This also means that compound assignment operations support lifted operations. w przykładzieIn the example

int? i = 0;
i += 1;             // Ok

użyto +(int?,int?) operatora, który został zniesiony.the lifted operator +(int?,int?) is used.

Przypisanie zdarzeniaEvent assignment

Jeśli argument operacji po lewej stronie operatora += lub -= został sklasyfikowany jako dostęp do zdarzenia, wyrażenie jest oceniane w następujący sposób:If the left operand of a += or -= operator is classified as an event access, then the expression is evaluated as follows:

  • Wyrażenie wystąpienia (jeśli istnieje) dostępu do zdarzenia jest oceniane.The instance expression, if any, of the event access is evaluated.
  • Jest oceniany prawy operand operatora += lub -=, a jeśli jest to wymagane, konwertowane na typ operandu lewego przez niejawną konwersję (konwersje niejawne).The right operand of the += or -= operator is evaluated, and, if required, converted to the type of the left operand through an implicit conversion (Implicit conversions).
  • Metoda dostępu do zdarzenia jest wywoływana, z listą argumentów składającą się z prawego operandu, po dokonaniu oceny i, w razie potrzeby, konwersji.An event accessor of the event is invoked, with argument list consisting of the right operand, after evaluation and, if necessary, conversion. Jeśli operator został +=, metoda dostępu add jest wywoływana; Jeśli operator został -=, metoda dostępu remove jest wywoływana.If the operator was +=, the add accessor is invoked; if the operator was -=, the remove accessor is invoked.

Wyrażenie przypisania zdarzenia nie zwraca wartości.An event assignment expression does not yield a value. W związku z tym wyrażenie przypisania zdarzenia jest prawidłowe tylko w kontekście statement_expression (instrukcji wyrażeń).Thus, an event assignment expression is valid only in the context of a statement_expression (Expression statements).

WyrażenieExpression

Wyrażenie jest non_assignment_expression lub przypisanie.An expression is either a non_assignment_expression or an assignment.

expression
    : non_assignment_expression
    | assignment
    ;

non_assignment_expression
    : conditional_expression
    | lambda_expression
    | query_expression
    ;

Wyrażenia stałeConstant expressions

Constant_expression jest wyrażeniem, które może być w pełni oceniane w czasie kompilacji.A constant_expression is an expression that can be fully evaluated at compile-time.

constant_expression
    : expression
    ;

Wyrażenie stałe musi być literałem null lub wartością z jednym z następujących typów: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, object, stringlub dowolnego typu wyliczenia.A constant expression must be the null literal or a value with one of the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, object, string, or any enumeration type. Tylko następujące konstrukcje są dozwolone w wyrażeniach stałych:Only the following constructs are permitted in constant expressions:

  • Literały (w tym literał null).Literals (including the null literal).
  • Odwołania do const składowych klas i typów struktury.References to const members of class and struct types.
  • Odwołania do elementów członkowskich typów wyliczeniowych.References to members of enumeration types.
  • Odwołania do parametrów const lub zmiennych lokalnychReferences to const parameters or local variables
  • Podwyrażenia w nawiasach, które są same wyrażeniami stałymi.Parenthesized sub-expressions, which are themselves constant expressions.
  • Wyrażenia rzutowania, pod warunkiem, że typ docelowy to jeden z typów wymienionych powyżej.Cast expressions, provided the target type is one of the types listed above.
  • wyrażenia checked i uncheckedchecked and unchecked expressions
  • Wyrażenia wartości domyślnychDefault value expressions
  • Wyrażenia nameofNameof expressions
  • Wstępnie zdefiniowane +, -, !i ~ operatory jednoargumentowe.The predefined +, -, !, and ~ unary operators.
  • Wstępnie zdefiniowane +, -, *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=i >= operatory binarne, pod warunkiem, że każdy operand jest typu wymienionego powyżej.The predefined +, -, *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, and >= binary operators, provided each operand is of a type listed above.
  • Operator warunkowy ?:.The ?: conditional operator.

Następujące konwersje są dozwolone w wyrażeniach stałych:The following conversions are permitted in constant expressions:

  • Konwersje tożsamościIdentity conversions
  • Konwersje numeryczneNumeric conversions
  • Konwersje wyliczeniaEnumeration conversions
  • Konwersje wyrażeń stałychConstant expression conversions
  • Konwersje niejawne i jawne, pod warunkiem, że źródło konwersji jest wyrażeniem stałym, którego wartość jest równa null.Implicit and explicit reference conversions, provided that the source of the conversions is a constant expression that evaluates to the null value.

Inne konwersje, w tym opakowanie, rozpakowywanie i niejawne konwersje odwołań wartości innych niż null, są niedozwolone w wyrażeniach stałych.Other conversions including boxing, unboxing and implicit reference conversions of non-null values are not permitted in constant expressions. Na przykład:For example:

class C {
    const object i = 5;         // error: boxing conversion not permitted
    const object str = "hello"; // error: implicit reference conversion
}

Inicjowanie i jest błędem, ponieważ wymagana jest konwersja z opakowaniem.the initialization of i is an error because a boxing conversion is required. Inicjalizacja str jest błędem, ponieważ wymagana jest niejawna konwersja odwołania z wartości innej niż null.The initialization of str is an error because an implicit reference conversion from a non-null value is required.

Gdy wyrażenie spełnia wymagania wymienione powyżej, wyrażenie jest oceniane w czasie kompilacji.Whenever an expression fulfills the requirements listed above, the expression is evaluated at compile-time. Jest to prawdziwe, nawet jeśli wyrażenie jest podwyrażeniem większego wyrażenia, które zawiera niestałe konstrukcje.This is true even if the expression is a sub-expression of a larger expression that contains non-constant constructs.

Ocena czasu kompilacji wyrażeń stałych używa tych samych zasad, co w przypadku oceny w czasie wykonywania wyrażeń niestałych, z tą różnicą, że w przypadku oceny czasu wykonywania wywołał wyjątek, Ocena czasu kompilacji powoduje wystąpienie błędu kompilacji.The compile-time evaluation of constant expressions uses the same rules as run-time evaluation of non-constant expressions, except that where run-time evaluation would have thrown an exception, compile-time evaluation causes a compile-time error to occur.

Jeśli wyrażenie stałe nie jest jawnie umieszczane w kontekście unchecked, nadmiary występują w operacjach arytmetycznych typu całkowitego i konwersje podczas obliczania czasu kompilacji wyrażenia zawsze powodują błędy czasu kompilacji (wyrażenia stałe).Unless a constant expression is explicitly placed in an unchecked context, overflows that occur in integral-type arithmetic operations and conversions during the compile-time evaluation of the expression always cause compile-time errors (Constant expressions).

Wyrażenia stałe występują w kontekstach wymienionych poniżej.Constant expressions occur in the contexts listed below. W tych kontekstach występuje błąd czasu kompilacji, jeśli wyrażenie nie może być w pełni oceniane w czasie kompilacji.In these contexts, a compile-time error occurs if an expression cannot be fully evaluated at compile-time.

  • Stałe deklaracje (stałe).Constant declarations (Constants).
  • Wyliczanie deklaracji elementów członkowskich (składowe