ClassesClasses

Uma classe é uma estrutura de dados que pode conter dados membros (campos e constantes), membros da função (métodos, propriedades, eventos, indexadores, operadores, construtores de instância, destruidores e construtores estáticos) e tipos aninhados.A class is a data structure that may contain data members (constants and fields), function members (methods, properties, events, indexers, operators, instance constructors, destructors and static constructors), and nested types. Tipos de classe dá suporte à herança, um mecanismo pelo qual uma classe derivada pode estender e especializar uma classe base.Class types support inheritance, a mechanism whereby a derived class can extend and specialize a base class.

Declarações de classeClass declarations

Um class_declaration é um type_declaration (as declarações de tipo) que declara uma nova classe.A class_declaration is a type_declaration (Type declarations) that declares a new class.

class_declaration
    : attributes? class_modifier* 'partial'? 'class' identifier type_parameter_list?
      class_base? type_parameter_constraints_clause* class_body ';'?
    ;

Um class_declaration consiste em um conjunto opcional de atributos (atributos), seguido por um conjunto opcional de class_modifiers (modificadores de classe), seguido por um recurso opcional partial modificador, seguido da palavra-chave class e uma identificador que nomeia a classe, seguida por um opcional type_parameter_list (parâmetros de tipo), seguido por um recurso opcional class_base especificação (da Base de dados de classe especificação), seguido por um conjunto opcional de type_parameter_constraints_clauses (restrições de parâmetro de tipo), seguido por um class_body (Classe corpo), opcionalmente seguido por um ponto e vírgula.A class_declaration consists of an optional set of attributes (Attributes), followed by an optional set of class_modifiers (Class modifiers), followed by an optional partial modifier, followed by the keyword class and an identifier that names the class, followed by an optional type_parameter_list (Type parameters), followed by an optional class_base specification (Class base specification) , followed by an optional set of type_parameter_constraints_clauses (Type parameter constraints), followed by a class_body (Class body), optionally followed by a semicolon.

Uma declaração de classe não pode fornecer type_parameter_constraints_clauses, a menos que ele também fornece um type_parameter_list.A class declaration cannot supply type_parameter_constraints_clauses unless it also supplies a type_parameter_list.

Uma declaração de classe que fornece um type_parameter_list é um declaração de classe genérica.A class declaration that supplies a type_parameter_list is a generic class declaration. Além disso, qualquer classe aninhada dentro de uma declaração de classe genérica ou uma declaração de struct genérico é em si uma declaração de classe genérica, já que os parâmetros de tipo para o tipo de conteúdo devem ser fornecidos para criar um tipo construído.Additionally, any class nested inside a generic class declaration or a generic struct declaration is itself a generic class declaration, since type parameters for the containing type must be supplied to create a constructed type.

Modificadores de classeClass modifiers

Um class_declaration opcionalmente pode incluir uma sequência de modificadores de classe:A class_declaration may optionally include a sequence of class modifiers:

class_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'abstract'
    | 'sealed'
    | 'static'
    | class_modifier_unsafe
    ;

Ele é um erro de tempo de compilação para o mesmo modificador aparecer várias vezes em uma declaração de classe.It is a compile-time error for the same modifier to appear multiple times in a class declaration.

O new modificador é permitido em classes aninhadas.The new modifier is permitted on nested classes. Especifica que a classe oculta um membro herdado com o mesmo nome, conforme descrito em o novo modificador.It specifies that the class hides an inherited member by the same name, as described in The new modifier. É um erro de tempo de compilação para o new modificador para aparecer em uma declaração de classe não é uma declaração de classe aninhada.It is a compile-time error for the new modifier to appear on a class declaration that is not a nested class declaration.

O public, protected, internal, e private modificadores de acessibilidade da classe de controle.The public, protected, internal, and private modifiers control the accessibility of the class. Dependendo do contexto no qual ocorre a declaração de classe, alguns desses modificadores não podem ter permissão (declarado acessibilidade).Depending on the context in which the class declaration occurs, some of these modifiers may not be permitted (Declared accessibility).

O abstract, sealed e static modificadores são discutidos nas seções a seguir.The abstract, sealed and static modifiers are discussed in the following sections.

Classes abstratasAbstract classes

O abstract modificador é usado para indicar que uma classe é incompleta e que ele é destinado a ser usado apenas como uma classe base.The abstract modifier is used to indicate that a class is incomplete and that it is intended to be used only as a base class. Uma classe abstrata é diferente de uma classe não abstrata das seguintes maneiras:An abstract class differs from a non-abstract class in the following ways:

  • Uma classe abstrata não pode ser instanciada diretamente, e é um erro de tempo de compilação para usar o new operador em uma classe abstrata.An abstract class cannot be instantiated directly, and it is a compile-time error to use the new operator on an abstract class. Embora seja possível ter variáveis e valores cujos tipos de tempo de compilação são abstratos, tais variáveis e valores serão necessariamente ser null ou contém referências às instâncias de classes não abstratas derivadas dos tipos abstratos.While it is possible to have variables and values whose compile-time types are abstract, such variables and values will necessarily either be null or contain references to instances of non-abstract classes derived from the abstract types.
  • Uma classe abstrata é permitida (mas não obrigatório) para conter membros abstratos.An abstract class is permitted (but not required) to contain abstract members.
  • Uma classe abstrata não pode ser sealed.An abstract class cannot be sealed.

Quando uma classe não abstrata é derivada de uma classe abstrata, a classe não abstrata deve incluir implementações reais de todos os membros abstratos herdados, substituindo, portanto, esses membros abstratos.When a non-abstract class is derived from an abstract class, the non-abstract class must include actual implementations of all inherited abstract members, thereby overriding those abstract members. No exemploIn the example

abstract class A
{
    public abstract void F();
}

abstract class B: A
{
    public void G() {}
}

class C: B
{
    public override void F() {
        // actual implementation of F
    }
}

a classe abstrata A apresenta um método abstrato F.the abstract class A introduces an abstract method F. Classe B apresenta um método adicional G, mas já que ele não fornece uma implementação de F, B também deve ser declarada como abstrata.Class B introduces an additional method G, but since it doesn't provide an implementation of F, B must also be declared abstract. Classe C substituições F e fornece uma implementação real.Class C overrides F and provides an actual implementation. Como não há nenhum membro abstrato na C, C é permitido (mas não obrigatório) a ser não abstrata.Since there are no abstract members in C, C is permitted (but not required) to be non-abstract.

Classes lacradasSealed classes

O sealed modificador é usado para evitar a derivação de uma classe.The sealed modifier is used to prevent derivation from a class. Ocorrerá um erro de tempo de compilação se uma classe selada for especificada como a classe base de outra classe.A compile-time error occurs if a sealed class is specified as the base class of another class.

Uma classe selada não pode ser também uma classe abstrata.A sealed class cannot also be an abstract class.

O sealed modificador é usado principalmente para evitar derivação não intencional, mas ele também permite que determinadas otimizações de tempo de execução.The sealed modifier is primarily used to prevent unintended derivation, but it also enables certain run-time optimizations. Em particular, como uma classe selada é conhecida nunca ter quaisquer classes derivadas, é possível transformar as invocações de membro de função virtual em instâncias de classe sealed em chamadas não virtuais.In particular, because a sealed class is known to never have any derived classes, it is possible to transform virtual function member invocations on sealed class instances into non-virtual invocations.

Classes estáticasStatic classes

O static modificador é usado para marcar a classe que está sendo declarada como um classe estática.The static modifier is used to mark the class being declared as a static class. Uma classe estática não pode ser instanciada, não pode ser usada como um tipo e pode conter apenas membros estáticos.A static class cannot be instantiated, cannot be used as a type and can contain only static members. Apenas uma classe estática pode conter declarações de métodos de extensão (métodos de extensão).Only a static class can contain declarations of extension methods (Extension methods).

Uma declaração de classe estática está sujeito às seguintes restrições:A static class declaration is subject to the following restrictions:

  • Uma classe estática não pode incluir um sealed ou abstract modificador.A static class may not include a sealed or abstract modifier. No entanto, observe que uma vez que uma classe estática não pode ser instanciada ou derivada, ele se comporta como se ele foi bloqueado e abstrato.Note, however, that since a static class cannot be instantiated or derived from, it behaves as if it was both sealed and abstract.
  • Uma classe estática não pode incluir um class_base especificação (classe base especificação) e não é possível especificar explicitamente uma classe base ou uma lista de interfaces implementadas.A static class may not include a class_base specification (Class base specification) and cannot explicitly specify a base class or a list of implemented interfaces. Uma classe estática herda implicitamente de tipo object.A static class implicitly inherits from type object.
  • Uma classe estática pode conter apenas membros estáticos (membros estáticos e de instância).A static class can only contain static members (Static and instance members). Observe que as constantes e tipos aninhados são classificados como membros estáticos.Note that constants and nested types are classified as static members.
  • Uma classe estática não pode ter membros com protected ou protected internal declarado de acessibilidade.A static class cannot have members with protected or protected internal declared accessibility.

Ele é um erro de tempo de compilação para violar qualquer uma dessas restrições.It is a compile-time error to violate any of these restrictions.

Uma classe estática não tem nenhum construtor de instância.A static class has no instance constructors. Não é possível declarar um construtor de instância em uma classe estática e nenhum construtor de instância padrão (1>construtores padrão) é fornecido para uma classe estática.It is not possible to declare an instance constructor in a static class, and no default instance constructor (Default constructors) is provided for a static class.

Os membros de uma classe estática não são automaticamente estáticos, e as declarações de membro devem incluir explicitamente um static modificador (exceto constantes e tipos aninhados).The members of a static class are not automatically static, and the member declarations must explicitly include a static modifier (except for constants and nested types). Quando uma classe é aninhada dentro de uma classe estática de externa, a classe aninhada não é uma classe estática, a menos que ele inclua explicitamente um static modificador.When a class is nested within a static outer class, the nested class is not a static class unless it explicitly includes a static modifier.

Referenciar tipos de classe estáticaReferencing static class types

Um namespace_or_type_name (nomes de Namespace e tipo) tem permissão para fazer referência a uma classe estática seA namespace_or_type_name (Namespace and type names) is permitted to reference a static class if

  • O namespace_or_type_name é o T em uma namespace_or_type_name do formulário T.I, ouThe namespace_or_type_name is the T in a namespace_or_type_name of the form T.I, or
  • O namespace_or_type_name é o T em uma typeof_expression (listas de argumentos1) do formulário typeof(T).The namespace_or_type_name is the T in a typeof_expression (Argument lists1) of the form typeof(T).

Um primary_expression (membros de função) tem permissão para fazer referência a uma classe estática seA primary_expression (Function members) is permitted to reference a static class if

Em qualquer outro contexto é um erro de tempo de compilação para fazer referência a uma classe estática.In any other context it is a compile-time error to reference a static class. Por exemplo, é um erro para uma classe estática para ser usado como uma classe base, um tipo constituinte (tipos aninhados) de um membro, um argumento de tipo genérico ou uma restrição de parâmetro de tipo.For example, it is an error for a static class to be used as a base class, a constituent type (Nested types) of a member, a generic type argument, or a type parameter constraint. Da mesma forma, uma classe estática não pode ser usada em um tipo de matriz, um tipo de ponteiro, uma new expressão, uma expressão de conversão, uma is expressão, um as expressão, um sizeof expressão ou uma expressão de valor padrão.Likewise, a static class cannot be used in an array type, a pointer type, a new expression, a cast expression, an is expression, an as expression, a sizeof expression, or a default value expression.

Modificador parcialPartial modifier

O partial modificador é usado para indicar que este class_declaration é uma declaração de tipo parcial.The partial modifier is used to indicate that this class_declaration is a partial type declaration. Combinam várias declarações de tipo parcial com o mesmo nome dentro de uma declaração de namespace ou tipo delimitador à declaração de um tipo de formulário, seguindo as regras especificadas na tipos parciais.Multiple partial type declarations with the same name within an enclosing namespace or type declaration combine to form one type declaration, following the rules specified in Partial types.

Tendo a declaração de uma classe distribuída em segmentos separados do texto do programa pode ser útil se esses segmentos são produzidos ou mantidos em diferentes contextos.Having the declaration of a class distributed over separate segments of program text can be useful if these segments are produced or maintained in different contexts. Por exemplo, uma parte de uma declaração de classe pode ser gerada, de máquina, enquanto o outro é criado manualmente.For instance, one part of a class declaration may be machine generated, whereas the other is manually authored. Separação textual dos dois impede que atualizações por um entrem em conflito com as atualizações por outros.Textual separation of the two prevents updates by one from conflicting with updates by the other.

Parâmetros de tipoType parameters

Um parâmetro de tipo é um identificador simples que denota um espaço reservado para um tipo de argumento fornecido para criar um tipo construído.A type parameter is a simple identifier that denotes a placeholder for a type argument supplied to create a constructed type. Um parâmetro de tipo é um espaço reservado formal para um tipo que será fornecido posteriormente.A type parameter is a formal placeholder for a type that will be supplied later. Por outro lado, um argumento de tipo (argumentos de tipo) é o tipo real que é substituído para o parâmetro de tipo quando um tipo construído é criado.By contrast, a type argument (Type arguments) is the actual type that is substituted for the type parameter when a constructed type is created.

type_parameter_list
    : '<' type_parameters '>'
    ;

type_parameters
    : attributes? type_parameter
    | type_parameters ',' attributes? type_parameter
    ;

type_parameter
    : identifier
    ;

Cada parâmetro de tipo em uma declaração de classe define um nome no espaço de declaração (declarações) dessa classe.Each type parameter in a class declaration defines a name in the declaration space (Declarations) of that class. Portanto, ele não pode ter o mesmo nome que outro parâmetro de tipo ou um membro declarado na classe.Thus, it cannot have the same name as another type parameter or a member declared in that class. Um parâmetro de tipo não pode ter o mesmo nome que o próprio tipo.A type parameter cannot have the same name as the type itself.

Especificação de classe baseClass base specification

Uma declaração de classe pode incluir um class_base especificação, que define a classe base direta da classe e as interfaces (Interfaces) diretamente implementado pela classe.A class declaration may include a class_base specification, which defines the direct base class of the class and the interfaces (Interfaces) directly implemented by the class.

class_base
    : ':' class_type
    | ':' interface_type_list
    | ':' class_type ',' interface_type_list
    ;

interface_type_list
    : interface_type (',' interface_type)*
    ;

A classe base especificada em uma declaração de classe pode ser um tipo de classe construído (construído tipos).The base class specified in a class declaration can be a constructed class type (Constructed types). Uma classe base não pode ser um parâmetro de tipo por conta própria, embora isso pode envolver os parâmetros de tipo que estão no escopo.A base class cannot be a type parameter on its own, though it can involve the type parameters that are in scope.

class Extend<V>: V {}            // Error, type parameter used as base class

Classes baseBase classes

Quando um class_type está incluído na class_base, ele especifica a classe base direta da classe que está sendo declarado.When a class_type is included in the class_base, it specifies the direct base class of the class being declared. Se uma declaração de classe não tiver nenhuma class_base, ou se o class_base listas apenas tipos de interface, a classe base direta é assumida ser object.If a class declaration has no class_base, or if the class_base lists only interface types, the direct base class is assumed to be object. Uma classe herda os membros de sua classe base direta, conforme descrito em herança.A class inherits members from its direct base class, as described in Inheritance.

No exemploIn the example

class A {}

class B: A {}

classe A deve ser a classe base direta do B, e B deve ser derivado de A.class A is said to be the direct base class of B, and B is said to be derived from A. Uma vez que A faz não explicitamente especificar uma classe base direta, sua classe base direta é implicitamente object.Since A does not explicitly specify a direct base class, its direct base class is implicitly object.

Para um tipo de classe construída, se uma classe base for especificada na declaração de classe genérica, a classe base do tipo construído é obtida pela substituição, para cada type_parameter na declaração de classe base, correspondente type_argument do tipo construído.For a constructed class type, if a base class is specified in the generic class declaration, the base class of the constructed type is obtained by substituting, for each type_parameter in the base class declaration, the corresponding type_argument of the constructed type. Dadas as declarações de classe genéricaGiven the generic class declarations

class B<U,V> {...}

class G<T>: B<string,T[]> {...}

a classe base do tipo construído G<int> seria B<string,int[]>.the base class of the constructed type G<int> would be B<string,int[]>.

A classe base direta de um tipo de classe deve ser pelo menos tão acessíveis quanto o próprio tipo de classe (domínios de acessibilidade).The direct base class of a class type must be at least as accessible as the class type itself (Accessibility domains). Por exemplo, é um erro de tempo de compilação para um public classe para derivar de uma private ou internal classe.For example, it is a compile-time error for a public class to derive from a private or internal class.

A classe base direta de um tipo de classe não deve ser qualquer um dos seguintes tipos: System.Array, System.Delegate, System.MulticastDelegate, System.Enum, ou System.ValueType.The direct base class of a class type must not be any of the following types: System.Array, System.Delegate, System.MulticastDelegate, System.Enum, or System.ValueType. Além disso, uma declaração de classe genérica não é possível usar System.Attribute como uma classe base direta ou indireta.Furthermore, a generic class declaration cannot use System.Attribute as a direct or indirect base class.

Ao determinar o significado da especificação de classe base direta A de uma classe B, a classe base direta de B temporariamente será considerado como object.While determining the meaning of the direct base class specification A of a class B, the direct base class of B is temporarily assumed to be object. Intuitivamente, isso garante que o significado de uma especificação de classe base não pode recursivamente depender de si mesma.Intuitively this ensures that the meaning of a base class specification cannot recursively depend on itself. O Exemplo:The example:

class A<T> {
   public class B {}
}

class C : A<C.B> {}

é um erro desde na especificação de classe base A<C.B> a classe base direta do C é considerado objecte, portanto, (pelas regras da nomes de Namespace e tipo) C não é considerado como ter um membro B.is in error since in the base class specification A<C.B> the direct base class of C is considered to be object, and hence (by the rules of Namespace and type names) C is not considered to have a member B.

As classes de base de um tipo de classe são a classe base direta e suas classes base.The base classes of a class type are the direct base class and its base classes. Em outras palavras, o conjunto de classes base é o fechamento transitivo da relação de classe base direta.In other words, the set of base classes is the transitive closure of the direct base class relationship. Referindo-se ao exemplo anterior, as classes base B estão A e object.Referring to the example above, the base classes of B are A and object. No exemploIn the example

class A {...}

class B<T>: A {...}

class C<T>: B<IComparable<T>> {...}

class D<T>: C<T[]> {...}

as classes base D<int> estão C<int[]>, B<IComparable<int[]>>, A, e object.the base classes of D<int> are C<int[]>, B<IComparable<int[]>>, A, and object.

Com exceção de classe object, cada tipo de classe tem exatamente uma classe base direta.Except for class object, every class type has exactly one direct base class. O object classe não tem nenhuma classe base direta e é a classe base definitiva de todas as outras classes.The object class has no direct base class and is the ultimate base class of all other classes.

Quando uma classe B deriva de uma classe A, ele é um erro de tempo de compilação para A depender B.When a class B derives from a class A, it is a compile-time error for A to depend on B. Uma classe depende diretamente sua classe base direta (se houver) e depende diretamente a classe dentro do qual ele está aninhado imediatamente (se houver).A class directly depends on its direct base class (if any) and directly depends on the class within which it is immediately nested (if any). Dada esta definição, o conjunto completo de classes dos quais depende de uma classe é o fechamento reflexivo e transitivo do depende diretamente relação.Given this definition, the complete set of classes upon which a class depends is the reflexive and transitive closure of the directly depends on relationship.

O exemploThe example

class A: A {}

está incorreto porque a classe depende em si.is erroneous because the class depends on itself. Da mesma forma, o exemploLikewise, the example

class A: B {}
class B: C {}
class C: A {}

é um erro porque as classes circularmente dependem em si.is in error because the classes circularly depend on themselves. Por fim, o exemploFinally, the example

class A: B.C {}

class B: A
{
    public class C {}
}

resulta em um erro de tempo de compilação porque A depende B.C (sua classe base direta), que depende B (sua classe delimitadora), que depende circularmente A.results in a compile-time error because A depends on B.C (its direct base class), which depends on B (its immediately enclosing class), which circularly depends on A.

Observe que uma classe não depende das classes que estão aninhadas dentro dele.Note that a class does not depend on the classes that are nested within it. No exemploIn the example

class A
{
    class B: A {}
}

B depende A (porque A é sua classe base direta e sua classe delimitadora), mas A não depende B (como B não é uma classe base nem uma classe delimitadora de A ).B depends on A (because A is both its direct base class and its immediately enclosing class), but A does not depend on B (since B is neither a base class nor an enclosing class of A). Portanto, o exemplo é válido.Thus, the example is valid.

Não é possível derivar de um sealed classe.It is not possible to derive from a sealed class. No exemploIn the example

sealed class A {}

class B: A {}            // Error, cannot derive from a sealed class

classe B é um erro porque ele tenta derivar a sealed classe A.class B is in error because it attempts to derive from the sealed class A.

Implementações de interfacesInterface implementations

Um class_base especificação pode incluir uma lista dos tipos de interface, na qual caso a classe deve implementar diretamente os tipos de interface fornecido.A class_base specification may include a list of interface types, in which case the class is said to directly implement the given interface types. Implementações de interface são discutidas mais detalhadamente em implementações de Interface.Interface implementations are discussed further in Interface implementations.

Restrições de parâmetro de tipoType parameter constraints

Declarações de tipo e método genéricas, opcionalmente, podem especificar restrições de parâmetro de tipo, incluindo type_parameter_constraints_clauses.Generic type and method declarations can optionally specify type parameter constraints by including type_parameter_constraints_clauses.

type_parameter_constraints_clause
    : 'where' type_parameter ':' type_parameter_constraints
    ;

type_parameter_constraints
    : primary_constraint
    | secondary_constraints
    | constructor_constraint
    | primary_constraint ',' secondary_constraints
    | primary_constraint ',' constructor_constraint
    | secondary_constraints ',' constructor_constraint
    | primary_constraint ',' secondary_constraints ',' constructor_constraint
    ;

primary_constraint
    : class_type
    | 'class'
    | 'struct'
    ;

secondary_constraints
    : interface_type
    | type_parameter
    | secondary_constraints ',' interface_type
    | secondary_constraints ',' type_parameter
    ;

constructor_constraint
    : 'new' '(' ')'
    ;

Cada type_parameter_constraints_clause consiste o token where, seguido do nome de um parâmetro de tipo, seguido por dois-pontos e a lista de restrições para parâmetro de tipo.Each type_parameter_constraints_clause consists of the token where, followed by the name of a type parameter, followed by a colon and the list of constraints for that type parameter. Pode haver no máximo um where cláusula para cada parâmetro de tipo e o where cláusulas podem ser listadas em qualquer ordem.There can be at most one where clause for each type parameter, and the where clauses can be listed in any order. Como o get e set tokens em um acessador de propriedade, o where token não é uma palavra-chave.Like the get and set tokens in a property accessor, the where token is not a keyword.

A lista de restrições fornecido em uma where cláusula pode incluir qualquer um dos componentes a seguir, nesta ordem: uma única restrição primária, uma ou mais restrições secundárias e a restrição de construtor, new().The list of constraints given in a where clause can include any of the following components, in this order: a single primary constraint, one or more secondary constraints, and the constructor constraint, new().

Uma restrição primária pode ser um tipo de classe ou o restrição de tipo de referência class ou o restrição de tipo de valor struct.A primary constraint can be a class type or the reference type constraint class or the value type constraint struct. Uma restrição secundária pode ser um type_parameter ou interface_type.A secondary constraint can be a type_parameter or interface_type.

A restrição de tipo de referência Especifica que um argumento de tipo usado para o parâmetro de tipo deve ser um tipo de referência.The reference type constraint specifies that a type argument used for the type parameter must be a reference type. Essa restrição atendem a todos os tipos de classe, tipos de interface, tipos de delegados, tipos de matriz e os parâmetros de tipo conhecidos por ser um tipo de referência (conforme definido abaixo).All class types, interface types, delegate types, array types, and type parameters known to be a reference type (as defined below) satisfy this constraint.

A restrição de tipo de valor Especifica que um argumento de tipo usado para o parâmetro de tipo deve ser um tipo de valor não anulável.The value type constraint specifies that a type argument used for the type parameter must be a non-nullable value type. Todos os tipos de struct não anuláveis, tipos enum e parâmetros de tipo com a restrição de tipo de valor satisfazem essa restrição.All non-nullable struct types, enum types, and type parameters having the value type constraint satisfy this constraint. Observe que, embora classificado como um tipo de valor, um tipo anulável (tipos anuláveis) não satisfaz a restrição de tipo de valor.Note that although classified as a value type, a nullable type (Nullable types) does not satisfy the value type constraint. Um parâmetro de tipo com a restrição de tipo de valor não pode ter também o constructor_constraint.A type parameter having the value type constraint cannot also have the constructor_constraint.

Tipos de ponteiro nunca são permitidos para alguns argumentos de tipo e não são considerados para satisfazer qualquer referência tipo ou valor restrições de tipo.Pointer types are never allowed to be type arguments and are not considered to satisfy either the reference type or value type constraints.

Se uma restrição é um tipo de classe, um tipo de interface ou um parâmetro de tipo, esse tipo Especifica um mínimo "tipo base" que deve oferecer suporte a cada argumento de tipo usado para esse parâmetro de tipo.If a constraint is a class type, an interface type, or a type parameter, that type specifies a minimal "base type" that every type argument used for that type parameter must support. Sempre que um tipo construído ou método genérico for usado, o argumento de tipo é verificado em relação às restrições no parâmetro de tipo em tempo de compilação.Whenever a constructed type or generic method is used, the type argument is checked against the constraints on the type parameter at compile-time. O argumento de tipo fornecido deve satisfazer as condições descritas atendendo às restrições de.The type argument supplied must satisfy the conditions described in Satisfying constraints.

Um class_type restrição deve satisfazer as regras a seguir:A class_type constraint must satisfy the following rules:

  • O tipo deve ser um tipo de classe.The type must be a class type.
  • O tipo não deve ser sealed.The type must not be sealed.
  • O tipo não deve ser um dos seguintes tipos: System.Array, System.Delegate, System.Enum, ou System.ValueType.The type must not be one of the following types: System.Array, System.Delegate, System.Enum, or System.ValueType.
  • O tipo não deve ser object.The type must not be object. Como todos os tipos derivam object, tal restrição não terá efeito algum se ele eram permitido.Because all types derive from object, such a constraint would have no effect if it were permitted.
  • No máximo uma restrição para um parâmetro de tipo determinado pode ser um tipo de classe.At most one constraint for a given type parameter can be a class type.

Um tipo especificado como uma interface_type restrição deve satisfazer as regras a seguir:A type specified as an interface_type constraint must satisfy the following rules:

  • O tipo deve ser um tipo de interface.The type must be an interface type.
  • Um tipo não deve ser especificado mais de uma vez em um determinado where cláusula.A type must not be specified more than once in a given where clause.

Em ambos os casos, a restrição pode envolver qualquer um dos parâmetros de tipo da declaração de método como parte de um tipo construído ou tipo associado e pode envolver o tipo que está sendo declarado.In either case, the constraint can involve any of the type parameters of the associated type or method declaration as part of a constructed type, and can involve the type being declared.

Qualquer tipo de classe ou interface especificado como uma restrição de parâmetro de tipo deve ser pelo menos tão acessível (restrições de acessibilidade) como o tipo genérico ou método que está sendo declarado.Any class or interface type specified as a type parameter constraint must be at least as accessible (Accessibility constraints) as the generic type or method being declared.

Um tipo especificado como uma type_parameter restrição deve satisfazer as regras a seguir:A type specified as a type_parameter constraint must satisfy the following rules:

  • O tipo deve ser um parâmetro de tipo.The type must be a type parameter.
  • Um tipo não deve ser especificado mais de uma vez em um determinado where cláusula.A type must not be specified more than once in a given where clause.

Além disso não deve haver nenhum ciclo no gráfico de dependência de parâmetros de tipo, em que a dependência é uma relação transitiva definida por:In addition there must be no cycles in the dependency graph of type parameters, where dependency is a transitive relation defined by:

  • Se um parâmetro de tipo T é usado como uma restrição de parâmetro de tipo S , em seguida, S depende T.If a type parameter T is used as a constraint for type parameter S then S depends on T.
  • Se um parâmetro de tipo S depende de um parâmetro de tipo T e T depende de um parâmetro de tipo U , em seguida, S depende U.If a type parameter S depends on a type parameter T and T depends on a type parameter U then S depends on U.

Dada essa relação, é um erro de tempo de compilação para um parâmetro de tipo depender de si mesma (direta ou indiretamente).Given this relation, it is a compile-time error for a type parameter to depend on itself (directly or indirectly).

Todas as restrições devem ser consistentes entre os parâmetros de tipo dependente.Any constraints must be consistent among dependent type parameters. Se o parâmetro de tipo S depende do parâmetro de tipo T então:If type parameter S depends on type parameter T then:

  • T não deve ter a restrição de tipo de valor.T must not have the value type constraint. Caso contrário, T efetivamente o está lacrado S seria forçado a ter o mesmo tipo que T, eliminando a necessidade de dois parâmetros de tipo.Otherwise, T is effectively sealed so S would be forced to be the same type as T, eliminating the need for two type parameters.
  • Se S tem a restrição de tipo de valor, em seguida, T não deve ter uma class_type restrição.If S has the value type constraint then T must not have a class_type constraint.
  • Se S tem uma class_type restrição A e T tem uma class_type restrição B e em seguida, deve haver uma conversão de identidade ou implícita fazer referência a conversão de A à B ou uma conversão de referência implícita da B para A.If S has a class_type constraint A and T has a class_type constraint B then there must be an identity conversion or implicit reference conversion from A to B or an implicit reference conversion from B to A.
  • Se S também depende do parâmetro de tipo U e U tem um class_type restrição A e T tem um class_type restrição B e em seguida, deve haver uma conversão de identidade ou uma conversão de referência implícita da A ao B ou uma conversão de referência implícita da B para A.If S also depends on type parameter U and U has a class_type constraint A and T has a class_type constraint B then there must be an identity conversion or implicit reference conversion from A to B or an implicit reference conversion from B to A.

Ele é válido para S tenha a restrição de tipo de valor e T ter restrição de tipo de referência.It is valid for S to have the value type constraint and T to have the reference type constraint. Efetivamente, isso limita T para os tipos System.Object, System.ValueType, System.Enume qualquer tipo de interface.Effectively this limits T to the types System.Object, System.ValueType, System.Enum, and any interface type.

Se o where cláusula para um parâmetro de tipo inclui uma restrição de construtor (que tem o formato new()), é possível usar o new operador para criar instâncias do tipo (deexpressõesdecriaçãodoobjeto).If the where clause for a type parameter includes a constructor constraint (which has the form new()), it is possible to use the new operator to create instances of the type (Object creation expressions). Qualquer tipo de argumento usado para um parâmetro de tipo com uma restrição de construtor deve ter um construtor sem parâmetros público (Este construtor implicitamente existe para qualquer tipo de valor) ou ser um parâmetro de tipo com a restrição de tipo de valor ou a restrição de construtor (consulte Restrições de parâmetro de tipo para obter detalhes).Any type argument used for a type parameter with a constructor constraint must have a public parameterless constructor (this constructor implicitly exists for any value type) or be a type parameter having the value type constraint or constructor constraint (see Type parameter constraints for details).

A seguir estão exemplos de restrições:The following are examples of constraints:

interface IPrintable
{
    void Print();
}

interface IComparable<T>
{
    int CompareTo(T value);
}

interface IKeyProvider<T>
{
    T GetKey();
}

class Printer<T> where T: IPrintable {...}

class SortedList<T> where T: IComparable<T> {...}

class Dictionary<K,V>
    where K: IComparable<K>
    where V: IPrintable, IKeyProvider<K>, new()
{
    ...
}

O exemplo a seguir está em erro, porque ele faz com que uma circularidade no grafo de dependência dos parâmetros de tipo:The following example is in error because it causes a circularity in the dependency graph of the type parameters:

class Circular<S,T>
    where S: T
    where T: S                // Error, circularity in dependency graph
{
    ...
}

Os exemplos a seguir ilustram situações inválidas adicionais:The following examples illustrate additional invalid situations:

class Sealed<S,T>
    where S: T
    where T: struct        // Error, T is sealed
{
    ...
}

class A {...}

class B {...}

class Incompat<S,T>
    where S: A, T
    where T: B                // Error, incompatible class-type constraints
{
    ...
}

class StructWithClass<S,T,U>
    where S: struct, T
    where T: U
    where U: A                // Error, A incompatible with struct
{
    ...
}

O efetivo classe base de um parâmetro de tipo T é definido da seguinte maneira:The effective base class of a type parameter T is defined as follows:

  • Se T não tem nenhuma restrição primária ou restrições de parâmetro de tipo, sua classe base eficaz é object.If T has no primary constraints or type parameter constraints, its effective base class is object.
  • Se T tem a restrição de tipo de valor, sua classe base eficaz é System.ValueType.If T has the value type constraint, its effective base class is System.ValueType.
  • Se T tem uma class_type restrição C , mas nenhum type_parameter restrições, sua classe base eficaz é C.If T has a class_type constraint C but no type_parameter constraints, its effective base class is C.
  • Se T não tem nenhum class_type restrição, mas tem um ou mais type_parameter restrições, sua classe base efetiva é o tipo mais contido (eliminada conversão operadores) no conjunto de classes base efetivos de seu type_parameter restrições.If T has no class_type constraint but has one or more type_parameter constraints, its effective base class is the most encompassed type (Lifted conversion operators) in the set of effective base classes of its type_parameter constraints. As regras de consistência se existe um tipo mais contido.The consistency rules ensure that such a most encompassed type exists.
  • Se T tem um class_type restrição e um ou mais type_parameter restrições, sua classe base efetiva é o tipo mais contido (eliminada conversão operadores) no conjunto que consiste o class_type restrição de T e as classes base efetivas de seu type_parameter restrições.If T has both a class_type constraint and one or more type_parameter constraints, its effective base class is the most encompassed type (Lifted conversion operators) in the set consisting of the class_type constraint of T and the effective base classes of its type_parameter constraints. As regras de consistência se existe um tipo mais contido.The consistency rules ensure that such a most encompassed type exists.
  • Se T tem a restrição de tipo de referência, mas não class_type restrições, sua classe base eficaz é object.If T has the reference type constraint but no class_type constraints, its effective base class is object.

Com a finalidade dessas regras, se T tem uma restrição V que é um value_type, em vez disso, use o tipo de base mais específico V que é um class_type.For the purpose of these rules, if T has a constraint V that is a value_type, use instead the most specific base type of V that is a class_type. Jamais pode acontecer em uma restrição explicitamente especificada, mas pode ocorrer quando as restrições de um método genérico são implicitamente herdadas por uma declaração de método de substituição ou uma implementação explícita de um método de interface.This can never happen in an explicitly given constraint, but may occur when the constraints of a generic method are implicitly inherited by an overriding method declaration or an explicit implementation of an interface method.

Essas regras garantem que a classe base eficaz é sempre uma class_type.These rules ensure that the effective base class is always a class_type.

O conjunto da interface efetivo de um parâmetro de tipo T é definido da seguinte maneira:The effective interface set of a type parameter T is defined as follows:

  • Se T não tem nenhum secondary_constraints, seu conjunto de interface efetiva está vazio.If T has no secondary_constraints, its effective interface set is empty.
  • Se T tem interface_type restrições, mas não type_parameter restrições, seu conjunto de interface eficaz é seu conjunto de interface_type restrições.If T has interface_type constraints but no type_parameter constraints, its effective interface set is its set of interface_type constraints.
  • Se T não tem nenhum interface_type restrições, mas tem type_parameter restrições, seu conjunto de interface eficaz é a união dos conjuntos interface efetivo de seu type_ parâmetro restrições.If T has no interface_type constraints but has type_parameter constraints, its effective interface set is the union of the effective interface sets of its type_parameter constraints.
  • Se T tem ambos interface_type restrições e type_parameter restrições, seu conjunto de interface eficaz é a união de seu conjunto de interface_type restrições e os conjuntos de interface efetivo de seu type_parameter restrições.If T has both interface_type constraints and type_parameter constraints, its effective interface set is the union of its set of interface_type constraints and the effective interface sets of its type_parameter constraints.

É um parâmetro de tipo conhecido por ser um tipo de referência se ele tem a restrição de tipo de referência ou não é de sua classe base efetivo object ou System.ValueType.A type parameter is known to be a reference type if it has the reference type constraint or its effective base class is not object or System.ValueType.

Valores de um tipo de parâmetro de tipo restrita podem ser usados para acessar os membros de instância implicados pelas restrições.Values of a constrained type parameter type can be used to access the instance members implied by the constraints. No exemploIn the example

interface IPrintable
{
    void Print();
}

class Printer<T> where T: IPrintable
{
    void PrintOne(T x) {
        x.Print();
    }
}

os métodos de IPrintable pode ser chamado diretamente nas x porque T é restrito para implementar sempre IPrintable.the methods of IPrintable can be invoked directly on x because T is constrained to always implement IPrintable.

Corpo da classeClass body

O class_body de uma classe define os membros dessa classe.The class_body of a class defines the members of that class.

class_body
    : '{' class_member_declaration* '}'
    ;

Tipos parciaisPartial types

Uma declaração de tipo pode ser dividida entre vários declarações de tipo parcial.A type declaration can be split across multiple partial type declarations. A declaração de tipo é construída de suas partes, seguindo as regras nesta seção, momento em que ele será tratado como uma única declaração durante o restante do processamento de tempo de compilação e tempo de execução do programa.The type declaration is constructed from its parts by following the rules in this section, whereupon it is treated as a single declaration during the remainder of the compile-time and run-time processing of the program.

Um class_declaration, struct_declaration ou interface_declaration representa uma declaração de tipo parcial se ela incluir um partial modificador.A class_declaration, struct_declaration or interface_declaration represents a partial type declaration if it includes a partial modifier. partial não é uma palavra-chave e atua apenas como um modificador se ela aparecer imediatamente antes de uma das palavras-chave class, struct ou interface em uma declaração de tipo, ou antes do tipo void em uma declaração de método.partial is not a keyword, and only acts as a modifier if it appears immediately before one of the keywords class, struct or interface in a type declaration, or before the type void in a method declaration. Em outros contextos, ele pode ser usado como um identificador normal.In other contexts it can be used as a normal identifier.

Cada parte de uma declaração de tipo parcial deve incluir um partial modificador.Each part of a partial type declaration must include a partial modifier. Ele deve ter o mesmo nome e ser declarado no mesmo namespace ou tipo de declaração como as outras partes.It must have the same name and be declared in the same namespace or type declaration as the other parts. O partial modificador indica que as partes adicionais da declaração de tipo podem existir em outro lugar, mas a existência de tais partes adicionais não é um requisito; ele é válido para um tipo com uma única declaração incluir o partial modificador.The partial modifier indicates that additional parts of the type declaration may exist elsewhere, but the existence of such additional parts is not a requirement; it is valid for a type with a single declaration to include the partial modifier.

Todas as partes de um tipo parcial devem ser compiladas juntos, de modo que as partes podem ser mescladas em tempo de compilação em uma única declaração de tipo.All parts of a partial type must be compiled together such that the parts can be merged at compile-time into a single type declaration. Especificamente, tipos parciais não permitem tipos já compilados seja estendida.Partial types specifically do not allow already compiled types to be extended.

Tipos aninhados podem ser declarados em várias partes, usando o partial modificador.Nested types may be declared in multiple parts by using the partial modifier. Normalmente, o tipo recipiente é declarado usando partial como bem e cada parte do tipo aninhado é declarado em uma parte diferente do tipo recipiente.Typically, the containing type is declared using partial as well, and each part of the nested type is declared in a different part of the containing type.

O partial modificador não é permitido em declarações de enum ou delegado.The partial modifier is not permitted on delegate or enum declarations.

AtributosAttributes

Os atributos de um tipo parcial são determinados pela combinação, em uma ordem não especificada, os atributos de cada uma das partes.The attributes of a partial type are determined by combining, in an unspecified order, the attributes of each of the parts. Se um atributo é colocado em várias partes, é equivalente a especificar o atributo várias vezes no tipo.If an attribute is placed on multiple parts, it is equivalent to specifying the attribute multiple times on the type. Por exemplo, as duas partes:For example, the two parts:

[Attr1, Attr2("hello")]
partial class A {}

[Attr3, Attr2("goodbye")]
partial class A {}

são equivalentes a uma declaração, como:are equivalent to a declaration such as:

[Attr1, Attr2("hello"), Attr3, Attr2("goodbye")]
class A {}

Combinam atributos em parâmetros de tipo de maneira semelhante.Attributes on type parameters combine in a similar fashion.

ModificadoresModifiers

Quando uma declaração de tipo parcial inclui uma especificação de acessibilidade (o public, protected, internal, e private modificadores) ele deve concordar com todas as outras partes que incluem uma especificação de acessibilidade.When a partial type declaration includes an accessibility specification (the public, protected, internal, and private modifiers) it must agree with all other parts that include an accessibility specification. Se nenhuma parte de um tipo parcial inclui uma especificação de acessibilidade, o tipo é determinado a acessibilidade padrão apropriado (declarado acessibilidade).If no part of a partial type includes an accessibility specification, the type is given the appropriate default accessibility (Declared accessibility).

Se um ou mais declarações parciais de um tipo aninhado incluem um new modificador, nenhum aviso é relatado se o tipo aninhado oculta um membro herdado (ocultando por meio da herança).If one or more partial declarations of a nested type include a new modifier, no warning is reported if the nested type hides an inherited member (Hiding through inheritance).

Se um ou mais declarações parciais de uma classe incluem uma abstract modificador, a classe será considerada abstrata (classes abstratas).If one or more partial declarations of a class include an abstract modifier, the class is considered abstract (Abstract classes). Caso contrário, a classe é considerada não-abstrata.Otherwise, the class is considered non-abstract.

Se um ou mais declarações parciais de uma classe incluem uma sealed modificador, a classe será considerada lacrado (lacrados classes).If one or more partial declarations of a class include a sealed modifier, the class is considered sealed (Sealed classes). Caso contrário, a classe é considerada sem lacre.Otherwise, the class is considered unsealed.

Observe que uma classe não pode ser abstract e sealed.Note that a class cannot be both abstract and sealed.

Quando o unsafe modificador é usado em uma declaração de tipo parcial, somente essa parte é considerada um contexto inseguro (contextos não seguros).When the unsafe modifier is used on a partial type declaration, only that particular part is considered an unsafe context (Unsafe contexts).

Parâmetros de tipo e restriçõesType parameters and constraints

Se um tipo genérico é declarado em várias partes, cada parte deve declarar os parâmetros de tipo.If a generic type is declared in multiple parts, each part must state the type parameters. Cada parte deve ter o mesmo número de parâmetros de tipo e o mesmo nome para cada parâmetro de tipo, em ordem.Each part must have the same number of type parameters, and the same name for each type parameter, in order.

Quando uma declaração de tipo genérico parcial inclui restrições (where cláusulas), as restrições devem concordar com todas as outras partes que incluem restrições.When a partial generic type declaration includes constraints (where clauses), the constraints must agree with all other parts that include constraints. Especificamente, cada parte que inclui as restrições deve ter restrições para o mesmo conjunto de parâmetros de tipo, e para cada parâmetro de tipo dos conjuntos de primário, secundário e restrições de construtor devem ser equivalente.Specifically, each part that includes constraints must have constraints for the same set of type parameters, and for each type parameter the sets of primary, secondary, and constructor constraints must be equivalent. Dois conjuntos de restrições são equivalentes se eles contiverem os mesmos membros.Two sets of constraints are equivalent if they contain the same members. Se nenhuma parte de um tipo genérico parcial especifica restrições de parâmetro de tipo, o tipo de parâmetros são considerados sem restrição.If no part of a partial generic type specifies type parameter constraints, the type parameters are considered unconstrained.

O exemploThe example

partial class Dictionary<K,V>
    where K: IComparable<K>
    where V: IKeyProvider<K>, IPersistable
{
    ...
}

partial class Dictionary<K,V>
    where V: IPersistable, IKeyProvider<K>
    where K: IComparable<K>
{
    ...
}

partial class Dictionary<K,V>
{
    ...
}

é correto porque as partes que incluem restrições (os dois primeiros) efetivamente especificam o mesmo conjunto de primário, secundário e restrições de construtor para o mesmo conjunto de parâmetros de tipo, respectivamente.is correct because those parts that include constraints (the first two) effectively specify the same set of primary, secondary, and constructor constraints for the same set of type parameters, respectively.

Classe baseBase class

Quando uma declaração de classe parcial inclui uma especificação de classe base, ele deve concordar com todas as outras partes que incluem uma especificação de classe base.When a partial class declaration includes a base class specification it must agree with all other parts that include a base class specification. Se nenhuma parte de uma classe parcial inclui uma especificação de classe base, torna-se a classe base System.Object (classes Base).If no part of a partial class includes a base class specification, the base class becomes System.Object (Base classes).

Interfaces baseBase interfaces

O conjunto de interfaces base para um tipo declarado em várias partes é a união das interfaces base especificada em cada parte.The set of base interfaces for a type declared in multiple parts is the union of the base interfaces specified on each part. Uma interface de base específica somente pode ser nomeada de uma vez em cada parte, mas é permitido para várias partes nomear as mesmas interfaces base.A particular base interface may only be named once on each part, but it is permitted for multiple parts to name the same base interface(s). Deve haver apenas uma implementação dos membros de uma determinada interface base.There must only be one implementation of the members of any given base interface.

No exemploIn the example

partial class C: IA, IB {...}

partial class C: IC {...}

partial class C: IA, IB {...}

o conjunto de interfaces base para a classe C está IA, IB, e IC.the set of base interfaces for class C is IA, IB, and IC.

Normalmente, cada parte fornece uma implementação de interface (s) declarado na parte em questão; No entanto, isso não é um requisito.Typically, each part provides an implementation of the interface(s) declared on that part; however, this is not a requirement. Uma parte pode fornecer a implementação de uma interface declarada em uma parte diferente:A part may provide the implementation for an interface declared on a different part:

partial class X
{
    int IComparable.CompareTo(object o) {...}
}

partial class X: IComparable
{
    ...
}

MembrosMembers

Com exceção dos métodos parciais (métodos parciais), o conjunto de membros de um tipo declarado em várias partes é simplesmente a união de conjunto de membros declarados em cada parte.With the exception of partial methods (Partial methods), the set of members of a type declared in multiple parts is simply the union of the set of members declared in each part. Os corpos de todas as partes da declaração do tipo compartilham o mesmo espaço de declaração (declarações) e o escopo de cada membro (escopos) estende a órgãos de desenvolvimento de todas as partes.The bodies of all parts of the type declaration share the same declaration space (Declarations), and the scope of each member (Scopes) extends to the bodies of all the parts. O domínio de acessibilidade de qualquer membro sempre inclui todas as partes do tipo delimitador; um private membro declarado em uma parte está livremente acessível de outra parte.The accessibility domain of any member always includes all the parts of the enclosing type; a private member declared in one part is freely accessible from another part. Ele é um erro de tempo de compilação para declarar o mesmo membro em mais de uma parte do tipo, a menos que esse membro é um tipo com o partial modificador.It is a compile-time error to declare the same member in more than one part of the type, unless that member is a type with the partial modifier.

partial class A
{
    int x;                     // Error, cannot declare x more than once

    partial class Inner        // Ok, Inner is a partial type
    {
        int y;
    }
}

partial class A
{
    int x;                     // Error, cannot declare x more than once

    partial class Inner        // Ok, Inner is a partial type
    {
        int z;
    }
}

A ordenação dos membros dentro de um tipo é raramente significativo ao código c#, mas pode ser significativo ao fazer interface com outras linguagens e ambientes.The ordering of members within a type is rarely significant to C# code, but may be significant when interfacing with other languages and environments. Nesses casos, a ordenação dos membros dentro de um tipo declarado em várias partes é indefinido.In these cases, the ordering of members within a type declared in multiple parts is undefined.

Métodos parciaisPartial methods

Métodos parciais podem ser definidos em uma parte de uma declaração de tipo e implementados em outro.Partial methods can be defined in one part of a type declaration and implemented in another. A implementação é opcional. Se nenhuma parte implementa o método parcial, a declaração de método parcial e todas as chamadas para ele são removidas da declaração de tipo resultante da combinação das partes.The implementation is optional; if no part implements the partial method, the partial method declaration and all calls to it are removed from the type declaration resulting from the combination of the parts.

Métodos parciais não é possível definir os modificadores de acesso, mas são implicitamente private.Partial methods cannot define access modifiers, but are implicitly private. Tipo de retorno deve ser void, e seus parâmetros não podem ter o out modificador.Their return type must be void, and their parameters cannot have the out modifier. O identificador partial é reconhecido como uma palavra-chave especial em uma declaração de método somente se ela aparecer imediatamente antes o void tipo; caso contrário, ele pode ser usado como um identificador normal.The identifier partial is recognized as a special keyword in a method declaration only if it appears right before the void type; otherwise it can be used as a normal identifier. Um método parcial não pode implementar métodos de interface explicitamente.A partial method cannot explicitly implement interface methods.

Há dois tipos de declaração de método parcial: Se o corpo da declaração do método é um ponto e vírgula, a declaração é considerada um definindo a declaração de método parcial.There are two kinds of partial method declarations: If the body of the method declaration is a semicolon, the declaration is said to be a defining partial method declaration. Se o corpo é fornecido como uma bloco, a declaração deve ser um implementar a declaração de método parcial.If the body is given as a block, the declaration is said to be an implementing partial method declaration. Entre as partes de uma declaração de tipo pode haver apenas uma definição de declaração de método parcial com uma determinada assinatura e pode haver apenas uma implementação de declaração de método parcial com uma determinada assinatura.Across the parts of a type declaration there can be only one defining partial method declaration with a given signature, and there can be only one implementing partial method declaration with a given signature. Se uma declaração de método parcial de implementação é fornecida, uma definição de declaração de método parcial correspondente deve existir e as declarações devem corresponder como especificado no seguinte:If an implementing partial method declaration is given, a corresponding defining partial method declaration must exist, and the declarations must match as specified in the following:

  • As declarações devem ter os mesmos modificadores (embora não necessariamente na mesma ordem), nome do método, o número de parâmetros de tipo e o número de parâmetros.The declarations must have the same modifiers (although not necessarily in the same order), method name, number of type parameters and number of parameters.
  • Parâmetros correspondentes nas declarações devem ter os mesmos modificadores (embora não necessariamente na mesma ordem) e os mesmos tipos (módulo diferenças nos nomes de parâmetro de tipo).Corresponding parameters in the declarations must have the same modifiers (although not necessarily in the same order) and the same types (modulo differences in type parameter names).
  • Parâmetros de tipo correspondente nas declarações devem ter as mesmas restrições (módulo diferenças nos nomes de parâmetro de tipo).Corresponding type parameters in the declarations must have the same constraints (modulo differences in type parameter names).

Uma declaração de método parcial de implementação pode aparecer na mesma parte da declaração de método parcial de definição correspondente.An implementing partial method declaration can appear in the same part as the corresponding defining partial method declaration.

Um método definição parcial participa da resolução de sobrecarga.Only a defining partial method participates in overload resolution. Portanto, se uma declaração de implementação é fornecida, expressões de invocação podem resolver para invocações de método parcial.Thus, whether or not an implementing declaration is given, invocation expressions may resolve to invocations of the partial method. Como um método parcial sempre retorna void, tais expressões de invocação sempre será instruções de expressão.Because a partial method always returns void, such invocation expressions will always be expression statements. Além disso, como um método parcial é implicitamente private, tais instruções sempre ocorrerá dentro de uma das partes da declaração de tipo dentro do qual o método parcial é declarado.Furthermore, because a partial method is implicitly private, such statements will always occur within one of the parts of the type declaration within which the partial method is declared.

Se nenhuma parte de uma declaração de tipo parcial contém uma declaração de implementação para um determinado método parcial, qualquer instrução de expressão invocá-lo é simplesmente removida da declaração de tipo combinado.If no part of a partial type declaration contains an implementing declaration for a given partial method, any expression statement invoking it is simply removed from the combined type declaration. Portanto, a expressão de invocação, incluindo todas as expressões constituintes, não tem nenhum efeito em tempo de execução.Thus the invocation expression, including any constituent expressions, has no effect at run-time. O método parcial em si também é removido e não será um membro da declaração de tipo combinado.The partial method itself is also removed and will not be a member of the combined type declaration.

Se existir uma declaração de implementação para um determinado método parcial, as invocações de métodos parciais são mantidas.If an implementing declaration exist for a given partial method, the invocations of the partial methods are retained. O método parcial dá origem a uma declaração de método, semelhante à declaração de método parcial de implementação, exceto os seguintes:The partial method gives rise to a method declaration similar to the implementing partial method declaration except for the following:

  • O partial modificador não está incluídoThe partial modifier is not included
  • Os atributos na declaração de método resultantes são os atributos combinados da definição e a declaração de método parcial de implementação em ordem não especificada.The attributes in the resulting method declaration are the combined attributes of the defining and the implementing partial method declaration in unspecified order. Duplicatas não são removidas.Duplicates are not removed.
  • Os atributos nos parâmetros de declaração de método resultantes são os atributos combinados dos parâmetros correspondentes da definição e a declaração de método parcial de implementação em ordem não especificada.The attributes on the parameters of the resulting method declaration are the combined attributes of the corresponding parameters of the defining and the implementing partial method declaration in unspecified order. Duplicatas não são removidas.Duplicates are not removed.

Se uma declaração de definição, mas não uma declaração de implementação é fornecido para um método parcial M, as seguintes restrições se aplicam:If a defining declaration but not an implementing declaration is given for a partial method M, the following restrictions apply:

Métodos parciais são úteis para permitir que uma parte de uma declaração de tipo para personalizar o comportamento da outra parte, por exemplo, aquele que é gerado por uma ferramenta.Partial methods are useful for allowing one part of a type declaration to customize the behavior of another part, e.g., one that is generated by a tool. Considere a seguinte declaração de classe parcial:Consider the following partial class declaration:

partial class Customer
{
    string name;

    public string Name {
        get { return name; }
        set {
            OnNameChanging(value);
            name = value;
            OnNameChanged();
        }

    }

    partial void OnNameChanging(string newName);

    partial void OnNameChanged();
}

Se essa classe será compilada sem outras partes, as declarações de método parcial a definição e suas invocações serão removidas e a declaração de classe combinado resultante será equivalente ao seguinte:If this class is compiled without any other parts, the defining partial method declarations and their invocations will be removed, and the resulting combined class declaration will be equivalent to the following:

class Customer
{
    string name;

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

Suponha que outra parte for fornecido, no entanto, que fornece declarações de implementação dos métodos parciais:Assume that another part is given, however, which provides implementing declarations of the partial methods:

partial class Customer
{
    partial void OnNameChanging(string newName)
    {
        Console.WriteLine("Changing " + name + " to " + newName);
    }

    partial void OnNameChanged()
    {
        Console.WriteLine("Changed to " + name);
    }
}

Em seguida, a declaração de classe combinado resultante será equivalente ao seguinte:Then the resulting combined class declaration will be equivalent to the following:

class Customer
{
    string name;

    public string Name {
        get { return name; }
        set {
            OnNameChanging(value);
            name = value;
            OnNameChanged();
        }

    }

    void OnNameChanging(string newName)
    {
        Console.WriteLine("Changing " + name + " to " + newName);
    }

    void OnNameChanged()
    {
        Console.WriteLine("Changed to " + name);
    }
}

Associação de nomeName binding

Embora cada parte de um tipo extensível deve ser declarado no mesmo namespace, as partes normalmente são gravadas dentro de declarações de namespace diferente.Although each part of an extensible type must be declared within the same namespace, the parts are typically written within different namespace declarations. Assim, diferentes using diretivas (diretivas Using) podem estar presentes para cada parte.Thus, different using directives (Using directives) may be present for each part. Ao interpretar os nomes simples (inferência) dentro de uma parte, apenas o using diretivas das ções do namespace delimitador essa parte são consideradas.When interpreting simple names (Type inference) within one part, only the using directives of the namespace declaration(s) enclosing that part are considered. Isso pode resultar no mesmo identificador de ter diferentes significados em partes diferentes:This may result in the same identifier having different meanings in different parts:

namespace N
{
    using List = System.Collections.ArrayList;

    partial class A
    {
        List x;                // x has type System.Collections.ArrayList
    }
}

namespace N
{
    using List = Widgets.LinkedList;

    partial class A
    {
        List y;                // y has type Widgets.LinkedList
    }
}

Membros de classeClass members

Os membros de uma classe consistem em membros introduzidos por seus class_member_declarations e os membros herdados da classe base direta.The members of a class consist of the members introduced by its class_member_declarations and the members inherited from the direct base class.

class_member_declaration
    : constant_declaration
    | field_declaration
    | method_declaration
    | property_declaration
    | event_declaration
    | indexer_declaration
    | operator_declaration
    | constructor_declaration
    | destructor_declaration
    | static_constructor_declaration
    | type_declaration
    ;

Os membros de um tipo de classe são divididos nas seguintes categorias:The members of a class type are divided into the following categories:

  • Constantes, que representam valores constantes associados com a classe (constantes).Constants, which represent constant values associated with the class (Constants).
  • Campos, que são as variáveis da classe (campos).Fields, which are the variables of the class (Fields).
  • Métodos que implementam o cálculos e ações que podem ser executadas pela classe (métodos).Methods, which implement the computations and actions that can be performed by the class (Methods).
  • Propriedades que definem as características de chamada e as ações associadas à leitura e gravação a essas características (propriedades).Properties, which define named characteristics and the actions associated with reading and writing those characteristics (Properties).
  • Eventos, que definem as notificações que podem ser geradas pela classe (eventos).Events, which define notifications that can be generated by the class (Events).
  • Indexadores, que permitem que instâncias da classe a serem indexados da mesma forma (sintaticamente) como matrizes (indexadores).Indexers, which permit instances of the class to be indexed in the same way (syntactically) as arrays (Indexers).
  • Operadores, que definem os operadores de expressão que podem ser aplicados a instâncias da classe (operadores).Operators, which define the expression operators that can be applied to instances of the class (Operators).
  • Construtores, que implementam as ações necessárias para inicializar instâncias da classe de instância (construtores de instância)Instance constructors, which implement the actions required to initialize instances of the class (Instance constructors)
  • Destruidores, que implementam as ações a serem executadas antes de instâncias da classe serem descartadas permanentemente (destruidores).Destructors, which implement the actions to be performed before instances of the class are permanently discarded (Destructors).
  • Construtores estáticos, que implementam as ações necessárias para inicializar a classe em si (construtores estáticos).Static constructors, which implement the actions required to initialize the class itself (Static constructors).
  • Tipos que representam os tipos que são locais para a classe (tipos aninhados).Types, which represent the types that are local to the class (Nested types).

Os membros que podem conter código executável são conhecidos coletivamente como o membros de função do tipo de classe.Members that can contain executable code are collectively known as the function members of the class type. Os membros da função de um tipo de classe são os métodos, propriedades, eventos, indexadores, operadores, construtores de instância, destruidores e construtores estáticos desse tipo de classe.The function members of a class type are the methods, properties, events, indexers, operators, instance constructors, destructors, and static constructors of that class type.

Um class_declaration cria um novo espaço de declaração (declarações) e o class_member_declarations imediatamente contido pelo classe _declaration introduzir novos membros nesse espaço de declaração.A class_declaration creates a new declaration space (Declarations), and the class_member_declarations immediately contained by the class_declaration introduce new members into this declaration space. As seguintes regras se aplicam a class_member_declarations:The following rules apply to class_member_declarations:

  • Construtores de instância, destruidores e construtores estáticos devem ter o mesmo nome que a classe delimitadora.Instance constructors, destructors and static constructors must have the same name as the immediately enclosing class. Todos os outros membros devem ter nomes que diferem do nome da classe delimitadora imediatamente.All other members must have names that differ from the name of the immediately enclosing class.
  • O nome de uma constante, campo, propriedade, evento ou tipo deve ser diferente dos nomes de todos os outros membros declarados na mesma classe.The name of a constant, field, property, event, or type must differ from the names of all other members declared in the same class.
  • O nome de um método deve ser diferente dos nomes de todos os outros não-métodos declarados na mesma classe.The name of a method must differ from the names of all other non-methods declared in the same class. Além disso, a assinatura (assinaturas e sobrecarga) de um método deve ser diferente das assinaturas de todos os outros métodos declarados na mesma classe, e dois métodos declarados na mesma classe não podem ter assinaturas que diferem apenas por ref e out.In addition, the signature (Signatures and overloading) of a method must differ from the signatures of all other methods declared in the same class, and two methods declared in the same class may not have signatures that differ solely by ref and out.
  • A assinatura de um construtor de instância deve ser diferente das assinaturas de todos os outros construtores de instância declarados na mesma classe e dois construtores declarados na mesma classe não podem ter assinaturas que diferem somente por ref e out.The signature of an instance constructor must differ from the signatures of all other instance constructors declared in the same class, and two constructors declared in the same class may not have signatures that differ solely by ref and out.
  • A assinatura de um indexador deve ser diferente das assinaturas de todos os outros indexadores declarados na mesma classe.The signature of an indexer must differ from the signatures of all other indexers declared in the same class.
  • A assinatura de um operador deve ser diferente das assinaturas de todos os outros operadores declarados na mesma classe.The signature of an operator must differ from the signatures of all other operators declared in the same class.

Os membros herdados de um tipo de classe (herança) não fazem parte do espaço da declaração de uma classe.The inherited members of a class type (Inheritance) are not part of the declaration space of a class. Portanto, uma classe derivada tem permissão para declarar um membro com o mesmo nome ou assinatura como um membro herdado (que na verdade oculta o membro herdado).Thus, a derived class is allowed to declare a member with the same name or signature as an inherited member (which in effect hides the inherited member).

O tipo de instânciaThe instance type

Cada declaração de classe tem um tipo de limite associado (associado e não associados a tipos), o tipo de instância.Each class declaration has an associated bound type (Bound and unbound types), the instance type. Para uma declaração de classe genérica, o tipo de instância é formado pela criação de um tipo construído (construído tipos) da declaração de tipo, com cada um do tipo fornecido argumentos que são correspondentes parâmetro de tipo.For a generic class declaration, the instance type is formed by creating a constructed type (Constructed types) from the type declaration, with each of the supplied type arguments being the corresponding type parameter. Como o tipo de instância usa os parâmetros de tipo, ele só pode ser usado em que os parâmetros de tipo estão no escopo; ou seja, dentro da declaração de classe.Since the instance type uses the type parameters, it can only be used where the type parameters are in scope; that is, inside the class declaration. O tipo de instância é o tipo de this para código escrito na declaração de classe.The instance type is the type of this for code written inside the class declaration. Para classes não genéricas, o tipo de instância é simplesmente a classe declarada.For non-generic classes, the instance type is simply the declared class. O exemplo a seguir mostra várias declarações de classe, juntamente com seus tipos de instância:The following shows several class declarations along with their instance types:

class A<T>                           // instance type: A<T>
{
    class B {}                       // instance type: A<T>.B
    class C<U> {}                    // instance type: A<T>.C<U>
}

class D {}                           // instance type: D

Membros de tipos construídosMembers of constructed types

Os membros não herdado de um tipo construído são obtidos pela substituição, para cada type_parameter na declaração de membro, correspondente type_argument do tipo construído.The non-inherited members of a constructed type are obtained by substituting, for each type_parameter in the member declaration, the corresponding type_argument of the constructed type. O processo de substituição se baseia o significado semântico de declarações de tipo e não é substituição simplesmente textual.The substitution process is based on the semantic meaning of type declarations, and is not simply textual substitution.

Por exemplo, dada a declaração de classe genéricaFor example, given the generic class declaration

class Gen<T,U>
{
    public T[,] a;
    public void G(int i, T t, Gen<U,T> gt) {...}
    public U Prop { get {...} set {...} }
    public int H(double d) {...}
}

o tipo construído Gen<int[],IComparable<string>> tem os seguintes membros:the constructed type Gen<int[],IComparable<string>> has the following members:

public int[,][] a;
public void G(int i, int[] t, Gen<IComparable<string>,int[]> gt) {...}
public IComparable<string> Prop { get {...} set {...} }
public int H(double d) {...}

O tipo do membro a na declaração de classe genérica Gen é "matriz bidimensional de T", de modo que o tipo do membro a no tipo construído acima é "matriz bidimensional de matriz unidimensional de int", ou int[,][].The type of the member a in the generic class declaration Gen is "two-dimensional array of T", so the type of the member a in the constructed type above is "two-dimensional array of one-dimensional array of int", or int[,][].

Dentro de membros da função de instância, o tipo de this é o tipo de instância (o tipo de instância) da declaração do recipiente.Within instance function members, the type of this is the instance type (The instance type) of the containing declaration.

Todos os membros de uma classe genérica podem usar parâmetros de tipo de qualquer classe delimitadora, diretamente ou como parte de um tipo construído.All members of a generic class can use type parameters from any enclosing class, either directly or as part of a constructed type. Quando um determinado fechada tipo construído (aberto e fechado tipos) é usado em tempo de execução, cada uso de um parâmetro de tipo é substituído com o argumento de tipo real fornecido para o tipo construído.When a particular closed constructed type (Open and closed types) is used at run-time, each use of a type parameter is replaced with the actual type argument supplied to the constructed type. Por exemplo:For example:

class C<V>
{
    public V f1;
    public C<V> f2 = null;

    public C(V x) {
        this.f1 = x;
        this.f2 = this;
    }
}

class Application
{
    static void Main() {
        C<int> x1 = new C<int>(1);
        Console.WriteLine(x1.f1);        // Prints 1

        C<double> x2 = new C<double>(3.1415);
        Console.WriteLine(x2.f1);        // Prints 3.1415
    }
}

HerançaInheritance

Uma classe herda os membros de seu tipo de classe base direta.A class inherits the members of its direct base class type. Herança significa que uma classe contém implicitamente todos os membros de seu tipo de classe base direta, exceto para os construtores de instância, destruidores e construtores estáticos da classe base.Inheritance means that a class implicitly contains all members of its direct base class type, except for the instance constructors, destructors and static constructors of the base class. Alguns aspectos importantes de herança são:Some important aspects of inheritance are:

  • A herança é transitiva.Inheritance is transitive. Se C deriva B, e B é derivado de A, em seguida, C herda os membros declarados na B , bem como os membros declarados na A.If C is derived from B, and B is derived from A, then C inherits the members declared in B as well as the members declared in A.
  • Uma classe derivada estende sua classe base direta.A derived class extends its direct base class. Uma classe derivada pode adicionar novos membros aos que ela herda, mas ela não pode remover a definição de um membro herdado.A derived class can add new members to those it inherits, but it cannot remove the definition of an inherited member.
  • Construtores de instância, destruidores e construtores estáticos não são herdados, mas são todos os outros membros, independentemente de sua acessibilidade declarada (acesso de membro).Instance constructors, destructors, and static constructors are not inherited, but all other members are, regardless of their declared accessibility (Member access). No entanto, dependendo de sua acessibilidade declarada, os membros herdados podem não estar acessíveis em uma classe derivada.However, depending on their declared accessibility, inherited members might not be accessible in a derived class.
  • Uma classe derivada pode ocultar (ocultando por meio da herança) membros herdados, declarando novos membros com o mesmo nome ou assinatura.A derived class can hide (Hiding through inheritance) inherited members by declaring new members with the same name or signature. Observe entretanto que ocultar um membro herdado não remove esse membro — ele apenas tornará esse membro inacessível diretamente por meio da classe derivada.Note however that hiding an inherited member does not remove that member—it merely makes that member inaccessible directly through the derived class.
  • Uma instância de uma classe contém um conjunto de todos os campos de instância declarada na classe e suas classes base e uma conversão implícita (conversões de referência implícita) existe a partir de um tipo de classe derivada para qualquer um dos seus tipos de classe base.An instance of a class contains a set of all instance fields declared in the class and its base classes, and an implicit conversion (Implicit reference conversions) exists from a derived class type to any of its base class types. Portanto, uma referência a uma instância de uma classe derivada pode ser tratada como uma referência a uma instância de qualquer uma das suas classes base.Thus, a reference to an instance of some derived class can be treated as a reference to an instance of any of its base classes.
  • Uma classe pode declarar indexadores, propriedades e métodos virtuais, e as classes derivadas podem substituir a implementação desses membros de função.A class can declare virtual methods, properties, and indexers, and derived classes can override the implementation of these function members. Isso permite que classes apresentam comportamento polimórfico, no qual as ações executadas por uma invocação de membro de função varia de acordo com o tipo de tempo de execução da instância por meio do qual esse membro da função é invocado.This enables classes to exhibit polymorphic behavior wherein the actions performed by a function member invocation varies depending on the run-time type of the instance through which that function member is invoked.

O membro herdado de um tipo de classe construída são os membros do tipo de classe base imediata (classes Base), que é encontrado, substituindo os argumentos de tipo do tipo construído para cada ocorrência do tipo correspondente parâmetros de class_base especificação.The inherited member of a constructed class type are the members of the immediate base class type (Base classes), which is found by substituting the type arguments of the constructed type for each occurrence of the corresponding type parameters in the class_base specification. Esses membros, por sua vez, são transformados pelo substituindo, para cada type_parameter na declaração de membro, correspondente type_argument dos class_base especificação.These members, in turn, are transformed by substituting, for each type_parameter in the member declaration, the corresponding type_argument of the class_base specification.

class B<U>
{
    public U F(long index) {...}
}

class D<T>: B<T[]>
{
    public T G(string s) {...}
}

No exemplo acima, o tipo construído D<int> tem um membro não herdado public int G(string s) obtidas substituindo o argumento de tipo int para o parâmetro de tipo T.In the above example, the constructed type D<int> has a non-inherited member public int G(string s) obtained by substituting the type argument int for the type parameter T. D<int> também tem um membro herdado da declaração de classe B.D<int> also has an inherited member from the class declaration B. Esse membro herdado é determinado pelo primeiro determinando o tipo de classe base B<int[]> dos D<int> substituindo int para T na especificação de classe base B<T[]>.This inherited member is determined by first determining the base class type B<int[]> of D<int> by substituting int for T in the base class specification B<T[]>. Em seguida, como um argumento de tipo para B, int[] substituirá U na public U F(long index), produzindo o membro herdado public int[] F(long index).Then, as a type argument to B, int[] is substituted for U in public U F(long index), yielding the inherited member public int[] F(long index).

O modificador newThe new modifier

Um class_member_declaration tem permissão para declarar um membro com o mesmo nome ou assinatura como um membro herdado.A class_member_declaration is permitted to declare a member with the same name or signature as an inherited member. Quando isso ocorrer, o membro da classe derivada é considerado ocultar membro da classe base.When this occurs, the derived class member is said to hide the base class member. Ocultar um membro herdado não é considerado um erro, mas ele faz com que o compilador emita um aviso.Hiding an inherited member is not considered an error, but it does cause the compiler to issue a warning. Para suprimir o aviso, a declaração do membro da classe derivada pode incluir um new modificador para indicar que o membro derivado destina-se para ocultar o membro base.To suppress the warning, the declaration of the derived class member can include a new modifier to indicate that the derived member is intended to hide the base member. Este tópico é discutido mais detalhadamente em ocultando por meio da herança.This topic is discussed further in Hiding through inheritance.

Se um new modificador é incluído em uma declaração que não oculta um membro herdado, um aviso para esse efeito é emitido.If a new modifier is included in a declaration that doesn't hide an inherited member, a warning to that effect is issued. Esse aviso é suprimido, removendo o new modificador.This warning is suppressed by removing the new modifier.

Modificadores de acessoAccess modifiers

Um class_member_declaration pode ter qualquer um dos cinco tipos possíveis de acessibilidade declarada (declarado acessibilidade): public, protected internal, protected, internal , ou private.A class_member_declaration can have any one of the five possible kinds of declared accessibility (Declared accessibility): public, protected internal, protected, internal, or private. Exceto para o protected internal combinação, é um erro de tempo de compilação para especificar mais de um modificador de acesso.Except for the protected internal combination, it is a compile-time error to specify more than one access modifier. Quando um class_member_declaration não inclui nenhum modificador de acesso, private será assumido.When a class_member_declaration does not include any access modifiers, private is assumed.

Tipos constituintesConstituent types

Tipos que são usados na declaração de membro são chamados os tipos de membros daquele membro.Types that are used in the declaration of a member are called the constituent types of that member. Os tipos possíveis constituintes são o tipo de uma constante, campo, propriedade, indexador ou evento, o tipo de retorno de um método ou operador e os tipos de parâmetro de um método, indexador, operador ou Construtor de instância.Possible constituent types are the type of a constant, field, property, event, or indexer, the return type of a method or operator, and the parameter types of a method, indexer, operator, or instance constructor. Os tipos constituintes de um membro devem ser pelo menos tão acessíveis quanto o próprio membro (restrições de acessibilidade).The constituent types of a member must be at least as accessible as that member itself (Accessibility constraints).

Membros estáticos e de instânciaStatic and instance members

Membros de uma classe são membros estáticos ou membros de instância.Members of a class are either static members or instance members. Em termos gerais, é útil pensar em membros estáticos como pertencente a tipos de classes e membros de instância como pertencentes a objetos (instâncias de tipos de classe).Generally speaking, it is useful to think of static members as belonging to class types and instance members as belonging to objects (instances of class types).

Quando uma declaração de campo, método, propriedade, evento, operador ou construtor inclui um static modificador, ele declara um membro estático.When a field, method, property, event, operator, or constructor declaration includes a static modifier, it declares a static member. Além disso, uma declaração de constante ou um tipo declara implicitamente um membro estático.In addition, a constant or type declaration implicitly declares a static member. Membros estáticos têm as seguintes características:Static members have the following characteristics:

  • Quando um membro estático M é referenciada em uma member_access (acesso de membro) do formulário E.M, E deve indicar um tipo que contém M.When a static member M is referenced in a member_access (Member access) of the form E.M, E must denote a type containing M. É um erro de tempo de compilação para E para denotar uma instância.It is a compile-time error for E to denote an instance.
  • Um campo estático identifica exatamente um local de armazenamento para serem compartilhados por todas as instâncias de um tipo de classe fechado.A static field identifies exactly one storage location to be shared by all instances of a given closed class type. Não importa quantas instâncias de um tipo de classe fechados são criadas, há sempre apenas uma cópia de um campo estático.No matter how many instances of a given closed class type are created, there is only ever one copy of a static field.
  • Um membro de função estática (método, propriedade, evento, operador ou construtor) não funciona em uma instância específica e é um erro de tempo de compilação para se referir a this em tal um membro da função.A static function member (method, property, event, operator, or constructor) does not operate on a specific instance, and it is a compile-time error to refer to this in such a function member.

Quando uma declaração de campo, método, propriedade, evento, indexador, construtor ou destruidor não incluir um static modificador, ele declara um membro de instância.When a field, method, property, event, indexer, constructor, or destructor declaration does not include a static modifier, it declares an instance member. (Um membro de instância é chamado, às vezes, um membro não estático.) Membros de instância têm as seguintes características:(An instance member is sometimes called a non-static member.) Instance members have the following characteristics:

  • Quando um membro de instância M é referenciada em uma member_access (acesso de membro) do formulário E.M, E preciso marcar uma instância de um tipo que contém M.When an instance member M is referenced in a member_access (Member access) of the form E.M, E must denote an instance of a type containing M. É um erro de tempo de associação para E para denotar um tipo.It is a binding-time error for E to denote a type.
  • Cada instância de uma classe contém um conjunto separado de todos os campos de instância da classe.Every instance of a class contains a separate set of all instance fields of the class.
  • Um membro de função de instância (método, propriedade, indexador, construtor de instância ou destruidor) opera em uma determinada instância da classe, e essa instância pode ser acessada como this (esse acesso).An instance function member (method, property, indexer, instance constructor, or destructor) operates on a given instance of the class, and this instance can be accessed as this (This access).

O exemplo a seguir ilustra as regras para acessar estáticas e membros de instância:The following example illustrates the rules for accessing static and instance members:

class Test
{
    int x;
    static int y;

    void F() {
        x = 1;            // Ok, same as this.x = 1
        y = 1;            // Ok, same as Test.y = 1
    }

    static void G() {
        x = 1;            // Error, cannot access this.x
        y = 1;            // Ok, same as Test.y = 1
    }

    static void Main() {
        Test t = new Test();
        t.x = 1;          // Ok
        t.y = 1;          // Error, cannot access static member through instance
        Test.x = 1;       // Error, cannot access instance member through type
        Test.y = 1;       // Ok
    }
}

O F método mostra que em um membro da função de instância, uma simple_name (nomes simples) pode ser usado para acessar membros de instância e membros estáticos.The F method shows that in an instance function member, a simple_name (Simple names) can be used to access both instance members and static members. O G método mostra que em um membro da função estática, é um erro de tempo de compilação para acessar um membro de instância por meio de um simple_name.The G method shows that in a static function member, it is a compile-time error to access an instance member through a simple_name. O Main método mostra que em um member_access (acesso de membro), membros de instância devem ser acessados por meio de instâncias e os membros estáticos devem ser acessados por meio de tipos.The Main method shows that in a member_access (Member access), instance members must be accessed through instances, and static members must be accessed through types.

Tipos aninhadosNested types

Um tipo declarado dentro de uma declaração de classe ou struct é chamado de um tipo aninhado.A type declared within a class or struct declaration is called a nested type. Um tipo que é declarado dentro de uma unidade de compilação ou namespace é chamado de um tipo não aninhado.A type that is declared within a compilation unit or namespace is called a non-nested type.

No exemploIn the example

using System;

class A
{
    class B
    {
        static void F() {
            Console.WriteLine("A.B.F");
        }
    }
}

classe B é um tipo aninhado porque é declarado na classe Ae a classe A é um tipo não aninhado porque é declarado dentro de uma unidade de compilação.class B is a nested type because it is declared within class A, and class A is a non-nested type because it is declared within a compilation unit.

Nome totalmente qualificadoFully qualified name

O nome totalmente qualificado (nomes totalmente qualificados) para um tipo aninhado é S.N onde S é o nome totalmente qualificado do tipo no qual tipo N é declarada.The fully qualified name (Fully qualified names) for a nested type is S.N where S is the fully qualified name of the type in which type N is declared.

Acessibilidade declaradaDeclared accessibility

Tipos aninhados não podem ter public ou internal declarado acessibilidade e ter internal declarado acessibilidade por padrão.Non-nested types can have public or internal declared accessibility and have internal declared accessibility by default. Tipos aninhados podem ter essas formas de acessibilidade declarada também, além de uma ou mais formas adicionais de acessibilidade declarada, dependendo se o tipo recipiente é uma classe ou struct:Nested types can have these forms of declared accessibility too, plus one or more additional forms of declared accessibility, depending on whether the containing type is a class or struct:

  • Um tipo aninhado que é declarado em uma classe pode ter qualquer um dos cinco formas de acessibilidade declarada (public, protected internal, protected, internal, ou private) e, como outros membros de classe, o padrão é private declarado acessibilidade.A nested type that is declared in a class can have any of five forms of declared accessibility (public, protected internal, protected, internal, or private) and, like other class members, defaults to private declared accessibility.
  • Um tipo aninhado que é declarado em um struct pode ter qualquer um dos três formas de acessibilidade declarada (public, internal, ou private) e, como outros membros de struct, o padrão é private declarado de acessibilidade.A nested type that is declared in a struct can have any of three forms of declared accessibility (public, internal, or private) and, like other struct members, defaults to private declared accessibility.

O exemploThe example

public class List
{
    // Private data structure
    private class Node
    { 
        public object Data;
        public Node Next;

        public Node(object data, Node next) {
            this.Data = data;
            this.Next = next;
        }
    }

    private Node first = null;
    private Node last = null;

    // Public interface
    public void AddToFront(object o) {...}
    public void AddToBack(object o) {...}
    public object RemoveFromFront() {...}
    public object RemoveFromBack() {...}
    public int Count { get {...} }
}

declara uma classe particular aninhada Node.declares a private nested class Node.

OcultandoHiding

Um tipo aninhado pode ocultar (ocultar nomes) um membro base.A nested type may hide (Name hiding) a base member. O new modificador é permitido em declarações de tipo aninhado, de modo que a ocultação de pode ser expressos explicitamente.The new modifier is permitted on nested type declarations so that hiding can be expressed explicitly. O exemploThe example

using System;

class Base
{
    public static void M() {
        Console.WriteLine("Base.M");
    }
}

class Derived: Base 
{
    new public class M 
    {
        public static void F() {
            Console.WriteLine("Derived.M.F");
        }
    }
}

class Test 
{
    static void Main() {
        Derived.M.F();
    }
}

mostra uma classe aninhada M que oculta o método M definidos no Base.shows a nested class M that hides the method M defined in Base.

Esse acessothis access

Um tipo aninhado e seu tipo recipiente não têm uma relação especial em relação ao this_access (esse acesso).A nested type and its containing type do not have a special relationship with regard to this_access (This access). Especificamente, this dentro de um tipo aninhado não pode ser usado para fazer referência a membros de instância do tipo recipiente.Specifically, this within a nested type cannot be used to refer to instance members of the containing type. Em casos onde um tipo aninhado precisa acessar os membros de instância de seu tipo recipiente, o acesso pode ser fornecido, fornecendo o this para a instância do tipo recipiente, como um argumento de construtor para o tipo aninhado.In cases where a nested type needs access to the instance members of its containing type, access can be provided by providing the this for the instance of the containing type as a constructor argument for the nested type. O exemplo a seguirThe following example

using System;

class C
{
    int i = 123;

    public void F() {
        Nested n = new Nested(this);
        n.G();
    }

    public class Nested
    {
        C this_c;

        public Nested(C c) {
            this_c = c;
        }

        public void G() {
            Console.WriteLine(this_c.i);
        }
    }
}

class Test
{
    static void Main() {
        C c = new C();
        c.F();
    }
}

mostra detalhes desta técnica.shows this technique. Uma instância do C cria uma instância do Nested e passa seu próprio this ao Nesteddo construtor para fornecer acesso subsequente ao Cdo membros da instância.An instance of C creates an instance of Nested and passes its own this to Nested's constructor in order to provide subsequent access to C's instance members.

Acesso a membros particulares e protegidos do tipo recipienteAccess to private and protected members of the containing type

Um tipo aninhado tem acesso a todos os membros que são acessíveis ao seu tipo recipiente, incluindo os membros do tipo recipiente que tenham private e protected declarado de acessibilidade.A nested type has access to all of the members that are accessible to its containing type, including members of the containing type that have private and protected declared accessibility. O exemploThe example

using System;

class C 
{
    private static void F() {
        Console.WriteLine("C.F");
    }

    public class Nested 
    {
        public static void G() {
            F();
        }
    }
}

class Test 
{
    static void Main() {
        C.Nested.G();
    }
}

mostra uma classe C que contém uma classe aninhada Nested.shows a class C that contains a nested class Nested. Dentro de Nested, o método G chama o método estático F definidos no C, e F privada declarou acessibilidade.Within Nested, the method G calls the static method F defined in C, and F has private declared accessibility.

Um tipo aninhado também pode acessar membros protegidos definidos em um tipo base do seu tipo recipiente.A nested type also may access protected members defined in a base type of its containing type. No exemploIn the example

using System;

class Base 
{
    protected void F() {
        Console.WriteLine("Base.F");
    }
}

class Derived: Base 
{
    public class Nested 
    {
        public void G() {
            Derived d = new Derived();
            d.F();        // ok
        }
    }
}

class Test 
{
    static void Main() {
        Derived.Nested n = new Derived.Nested();
        n.G();
    }
}

a classe aninhada Derived.Nested acessa o método protegido F definidos no Derivedda classe base Base, por chamada por meio de uma instância de Derived.the nested class Derived.Nested accesses the protected method F defined in Derived's base class, Base, by calling through an instance of Derived.

Tipos aninhados nas classes genéricasNested types in generic classes

Uma declaração de classe genérica pode conter declarações de tipo aninhado.A generic class declaration can contain nested type declarations. Os parâmetros de tipo da classe delimitadora podem ser usados dentro dos tipos aninhados.The type parameters of the enclosing class can be used within the nested types. Uma declaração de tipo aninhado pode conter parâmetros de tipo adicionais que se aplicam somente ao tipo aninhado.A nested type declaration can contain additional type parameters that apply only to the nested type.

Cada declaração de tipo contida dentro de uma declaração de classe genérica é implicitamente uma declaração de tipo genérico.Every type declaration contained within a generic class declaration is implicitly a generic type declaration. Quando escrever uma referência a um tipo aninhado dentro de um tipo genérico, tipo construído recipiente, incluindo seus argumentos de tipo deve ser nomeado.When writing a reference to a type nested within a generic type, the containing constructed type, including its type arguments, must be named. No entanto, de dentro da classe externa, o tipo aninhado pode ser usado sem qualificação; o tipo de instância da classe externa pode ser usado implicitamente ao construir o tipo aninhado.However, from within the outer class, the nested type can be used without qualification; the instance type of the outer class can be implicitly used when constructing the nested type. O exemplo a seguir mostra três maneiras diferentes de corretas para se referir a um tipo construído criado a partir de Inner; as duas primeiras são equivalentes:The following example shows three different correct ways to refer to a constructed type created from Inner; the first two are equivalent:

class Outer<T>
{
    class Inner<U>
    {
        public static void F(T t, U u) {...}
    }

    static void F(T t) {
        Outer<T>.Inner<string>.F(t, "abc");      // These two statements have
        Inner<string>.F(t, "abc");               // the same effect

        Outer<int>.Inner<string>.F(3, "abc");    // This type is different

        Outer.Inner<string>.F(t, "abc");         // Error, Outer needs type arg
    }
}

Embora seja ruim programação estilo, um parâmetro de tipo em um tipo aninhado pode ocultar um membro ou parâmetro declarado no tipo externo do tipo:Although it is bad programming style, a type parameter in a nested type can hide a member or type parameter declared in the outer type:

class Outer<T>
{
    class Inner<T>        // Valid, hides Outer's T
    {
        public T t;       // Refers to Inner's T
    }
}

Nomes de membro reservadoReserved member names

Para facilitar a c# tempo de execução implementação subjacente, para cada declaração de membro de origem é uma propriedade, evento ou indexador, a implementação deverá reservar duas assinaturas de método com base no tipo de declaração do membro, seu nome e seu tipo.To facilitate the underlying C# run-time implementation, for each source member declaration that is a property, event, or indexer, the implementation must reserve two method signatures based on the kind of the member declaration, its name, and its type. Ele é um erro de tempo de compilação para um programa declarar um membro cuja assinatura coincide com uma destas opções reservadas assinaturas, mesmo se a implementação de tempo de execução subjacente não faz uso dessas reservas.It is a compile-time error for a program to declare a member whose signature matches one of these reserved signatures, even if the underlying run-time implementation does not make use of these reservations.

Os nomes reservados não introduzem declarações, portanto, eles não participam de pesquisa de membro.The reserved names do not introduce declarations, thus they do not participate in member lookup. No entanto, uma declaração associada ao método reservado assinaturas participem da herança (herança) e pode ser ocultada com o new modificador (o novo modificador).However, a declaration's associated reserved method signatures do participate in inheritance (Inheritance), and can be hidden with the new modifier (The new modifier).

A reserva desses nomes atende a três propósitos:The reservation of these names serves three purposes:

  • Para permitir que a implementação subjacente usar um identificador comum como um nome de método para obter ou definir o acesso para o recurso de linguagem c#.To allow the underlying implementation to use an ordinary identifier as a method name for get or set access to the C# language feature.
  • Para permitir que outras linguagens interoperar usando um identificador comum como um nome de método para obter ou definir o acesso para o recurso de linguagem c#.To allow other languages to interoperate using an ordinary identifier as a method name for get or set access to the C# language feature.
  • Para ajudar a garantir que o código-fonte aceitos por um compilador de conformidade é aceito por outro, fazendo as especificidades do membro reservado nomes consistentes em todas as implementações do c#.To help ensure that the source accepted by one conforming compiler is accepted by another, by making the specifics of reserved member names consistent across all C# implementations.

A declaração de um destruidor (destruidores) também faz com que uma assinatura a ser reservado (nomes de membro reservados para os destruidores).The declaration of a destructor (Destructors) also causes a signature to be reserved (Member names reserved for destructors).

Nomes de membro para propriedades reservadosMember names reserved for properties

Para uma propriedade P (Properties) do tipo T, as assinaturas a seguir são reservadas:For a property P (Properties) of type T, the following signatures are reserved:

T get_P();
void set_P(T value);

Ambas as assinaturas são reservadas, mesmo se a propriedade é somente leitura ou somente gravação.Both signatures are reserved, even if the property is read-only or write-only.

No exemploIn the example

using System;

class A
{
    public int P {
        get { return 123; }
    }
}

class B: A
{
    new public int get_P() {
        return 456;
    }

    new public void set_P(int value) {
    }
}

class Test
{
    static void Main() {
        B b = new B();
        A a = b;
        Console.WriteLine(a.P);
        Console.WriteLine(b.P);
        Console.WriteLine(b.get_P());
    }
}

uma classe A define uma propriedade somente leitura P, assim, reservando assinaturas para get_P e set_P métodos.a class A defines a read-only property P, thus reserving signatures for get_P and set_P methods. Uma classe B deriva A e oculta a ambas as assinaturas reservadas.A class B derives from A and hides both of these reserved signatures. O exemplo produz a saída:The example produces the output:

123
123
456

Nomes de membro reservados para eventosMember names reserved for events

Para um evento E (eventos) de tipo de delegado T, as assinaturas a seguir são reservadas:For an event E (Events) of delegate type T, the following signatures are reserved:

void add_E(T handler);
void remove_E(T handler);

Nomes de membro reservados para indexadoresMember names reserved for indexers

Para um indexador (indexadores) do tipo T com a lista de parâmetros L, as assinaturas a seguir são reservadas:For an indexer (Indexers) of type T with parameter-list L, the following signatures are reserved:

T get_Item(L);
void set_Item(L, T value);

Ambas as assinaturas são reservadas, mesmo que o indexador é somente leitura ou somente gravação.Both signatures are reserved, even if the indexer is read-only or write-only.

Além do nome do membro Item é reservado.Furthermore the member name Item is reserved.

Nomes de membro reservados para os destruidoresMember names reserved for destructors

Para uma classe que contém um destruidor (destruidores), a assinatura a seguir é reservada:For a class containing a destructor (Destructors), the following signature is reserved:

void Finalize();

ConstantesConstants

Um constante é um membro da classe que representa um valor constante: um valor que pode ser calculado em tempo de compilação.A constant is a class member that represents a constant value: a value that can be computed at compile-time. Um constant_declaration introduz uma ou mais constantes de um determinado tipo.A constant_declaration introduces one or more constants of a given type.

constant_declaration
    : attributes? constant_modifier* 'const' type constant_declarators ';'
    ;

constant_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    ;

constant_declarators
    : constant_declarator (',' constant_declarator)*
    ;

constant_declarator
    : identifier '=' constant_expression
    ;

Um constant_declaration pode incluir um conjunto de atributos (atributos), um new modificador (o novo modificador), e uma combinação válida de as quatro modificadores de acesso (modificadores de acesso).A constant_declaration may include a set of attributes (Attributes), a new modifier (The new modifier), and a valid combination of the four access modifiers (Access modifiers). Os atributos e modificadores que se aplicam a todos os membros declarados pela constant_declaration.The attributes and modifiers apply to all of the members declared by the constant_declaration. Mesmo que as constantes são consideradas membros estáticos, um constant_declaration não exige nem permite que um static modificador.Even though constants are considered static members, a constant_declaration neither requires nor allows a static modifier. É um erro para o mesmo modificador aparecer várias vezes em uma declaração de constante.It is an error for the same modifier to appear multiple times in a constant declaration.

O tipo de uma constant_declaration Especifica o tipo dos membros apresentados pela declaração.The type of a constant_declaration specifies the type of the members introduced by the declaration. O tipo é seguido por uma lista de constant_declarators, cada uma delas apresenta um novo membro.The type is followed by a list of constant_declarators, each of which introduces a new member. Um constant_declarator consiste em um identificador que nomeia o membro, seguido por um "=" token, seguido por um constant_expression ( Expressões de constante) que fornece o valor do membro.A constant_declarator consists of an identifier that names the member, followed by an "=" token, followed by a constant_expression (Constant expressions) that gives the value of the member.

O tipo especificado em uma constante de declaração deve ser sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, uma enum_type, ou um reference_type.The type specified in a constant declaration must be sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, an enum_type, or a reference_type. Cada constant_expression deve produzir um valor do tipo de destino ou de um tipo que pode ser convertido para o tipo de destino por uma conversão implícita (conversões implícitas).Each constant_expression must yield a value of the target type or of a type that can be converted to the target type by an implicit conversion (Implicit conversions).

O tipo de uma constante deve ser pelo menos tão acessível quanto a própria constante (restrições de acessibilidade).The type of a constant must be at least as accessible as the constant itself (Accessibility constraints).

O valor de uma constante é obtido em uma expressão que usa um simple_name (nomes simples) ou uma member_access (acesso de membro).The value of a constant is obtained in an expression using a simple_name (Simple names) or a member_access (Member access).

Uma constante em si pode participar em uma constant_expression.A constant can itself participate in a constant_expression. Portanto, uma constante pode ser usada em qualquer construção que requer uma constant_expression.Thus, a constant may be used in any construct that requires a constant_expression. Exemplos de tais construções case rótulos goto case instruções, enum declarações de membros, atributos e outras declarações de constante.Examples of such constructs include case labels, goto case statements, enum member declarations, attributes, and other constant declarations.

Conforme descrito em expressões constantes, um constant_expression é uma expressão que pode ser completamente avaliada em tempo de compilação.As described in Constant expressions, a constant_expression is an expression that can be fully evaluated at compile-time. Como o único modo para criar um valor não nulo de uma reference_type diferente de string é aplicar o new operador e desde o new operador não é permitido em um constant_ expressão, o único valor possível para constantes de reference_types diferente string é null.Since the only way to create a non-null value of a reference_type other than string is to apply the new operator, and since the new operator is not permitted in a constant_expression, the only possible value for constants of reference_types other than string is null.

Quando um nome simbólico para um valor constante for desejado, mas quando o tipo de valor não é permitido em uma declaração de constante, ou quando o valor não pode ser calculado em tempo de compilação por um constant_expression, um readonly (de campo Campos somente leitura) pode ser usado em vez disso.When a symbolic name for a constant value is desired, but when the type of that value is not permitted in a constant declaration, or when the value cannot be computed at compile-time by a constant_expression, a readonly field (Readonly fields) may be used instead.

Uma declaração de constante que declara várias constantes é equivalente a várias declarações de constantes únicos com o mesmo atributos, modificadores e tipo.A constant declaration that declares multiple constants is equivalent to multiple declarations of single constants with the same attributes, modifiers, and type. Por exemploFor example

class A
{
    public const double X = 1.0, Y = 2.0, Z = 3.0;
}

equivale ais equivalent to

class A
{
    public const double X = 1.0;
    public const double Y = 2.0;
    public const double Z = 3.0;
}

Constantes são permitidas para dependem outras constantes dentro do mesmo programa, desde que as dependências não são de natureza circular.Constants are permitted to depend on other constants within the same program as long as the dependencies are not of a circular nature. O compilador organiza automaticamente para avaliar as declarações de constante na ordem apropriada.The compiler automatically arranges to evaluate the constant declarations in the appropriate order. No exemploIn the example

class A
{
    public const int X = B.Z + 1;
    public const int Y = 10;
}

class B
{
    public const int Z = A.Y + 1;
}

o compilador primeiro avalia A.Y, em seguida, avalia B.Ze finalmente avalia A.X, produzindo os valores 10, 11, e 12.the compiler first evaluates A.Y, then evaluates B.Z, and finally evaluates A.X, producing the values 10, 11, and 12. Declarações de constante podem depender de constantes de outros programas, mas essas dependências só são possíveis em uma única direção.Constant declarations may depend on constants from other programs, but such dependencies are only possible in one direction. Referindo-se ao exemplo acima, se A e B foram declarados em programas separados, seria possível A.X depender B.Z, mas B.Z poderia, em seguida, não simultaneamente dependem A.Y.Referring to the example above, if A and B were declared in separate programs, it would be possible for A.X to depend on B.Z, but B.Z could then not simultaneously depend on A.Y.

CamposFields

Um campo é um membro que representa uma variável associada a um objeto ou classe.A field is a member that represents a variable associated with an object or class. Um field_declaration apresenta um ou mais campos de um determinado tipo.A field_declaration introduces one or more fields of a given type.

field_declaration
    : attributes? field_modifier* type variable_declarators ';'
    ;

field_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'readonly'
    | 'volatile'
    | field_modifier_unsafe
    ;

variable_declarators
    : variable_declarator (',' variable_declarator)*
    ;

variable_declarator
    : identifier ('=' variable_initializer)?
    ;

variable_initializer
    : expression
    | array_initializer
    ;

Um field_declaration pode incluir um conjunto de atributos (atributos), um new modificador (o novo modificador), um uma combinação válida de quatro modificadores de acesso (modificadores de acesso) e uma static modificador (campos estáticos e de instância).A field_declaration may include a set of attributes (Attributes), a new modifier (The new modifier), a valid combination of the four access modifiers (Access modifiers), and a static modifier (Static and instance fields). Além disso, uma field_declaration pode incluir uma readonly modificador (campos somente leitura) ou um volatile modificador (campos voláteis), mas não ambos.In addition, a field_declaration may include a readonly modifier (Readonly fields) or a volatile modifier (Volatile fields) but not both. Os atributos e modificadores que se aplicam a todos os membros declarados pela field_declaration.The attributes and modifiers apply to all of the members declared by the field_declaration. É um erro para o mesmo modificador aparecer várias vezes em uma declaração de campo.It is an error for the same modifier to appear multiple times in a field declaration.

O tipo de uma field_declaration Especifica o tipo dos membros apresentados pela declaração.The type of a field_declaration specifies the type of the members introduced by the declaration. O tipo é seguido por uma lista de variable_declarators, cada uma delas apresenta um novo membro.The type is followed by a list of variable_declarators, each of which introduces a new member. Um variable_declarator consiste em um identificador que nomeia esse membro, opcionalmente seguido por um "=" token e uma variable_initializer ( Inicializadores de variável) que fornece o valor inicial desse membro.A variable_declarator consists of an identifier that names that member, optionally followed by an "=" token and a variable_initializer (Variable initializers) that gives the initial value of that member.

O tipo de um campo deve ser pelo menos tão acessíveis quanto o próprio campo (restrições de acessibilidade).The type of a field must be at least as accessible as the field itself (Accessibility constraints).

O valor de um campo é obtido em uma expressão que usa um simple_name (nomes simples) ou uma member_access (acesso de membro).The value of a field is obtained in an expression using a simple_name (Simple names) or a member_access (Member access). O valor de um campo não readonly é modificado usando um atribuição (operadores de atribuição).The value of a non-readonly field is modified using an assignment (Assignment operators). O valor de um campo não readonly pode ser obtida e modificados usando incremento de sufixo e operadores de decremento (incremento de sufixo e operadores de decremento) e o incremento de prefixo e operadores de decremento (prefixo operadores de incremento e decremento).The value of a non-readonly field can be both obtained and modified using postfix increment and decrement operators (Postfix increment and decrement operators) and prefix increment and decrement operators (Prefix increment and decrement operators).

Uma declaração de campo que declara vários campos é equivalente a várias declarações de campos únicos com o mesmo atributos, modificadores e tipo.A field declaration that declares multiple fields is equivalent to multiple declarations of single fields with the same attributes, modifiers, and type. Por exemploFor example

class A
{
    public static int X = 1, Y, Z = 100;
}

equivale ais equivalent to

class A
{
    public static int X = 1;
    public static int Y;
    public static int Z = 100;
}

Campos estáticos e de instânciaStatic and instance fields

Quando uma declaração de campo inclui um static modificador, os campos apresentados pela declaração estão campos estáticos.When a field declaration includes a static modifier, the fields introduced by the declaration are static fields. Quando nenhum static modificador estiver presente, os campos apresentados pela declaração estão campos de instância.When no static modifier is present, the fields introduced by the declaration are instance fields. Campos estáticos e campos de instância são dois dos vários tipos de variáveis (variáveis) comportados pelo c# e às vezes eles são denominados variáveis estáticas e variáveis de instância , respectivamente.Static fields and instance fields are two of the several kinds of variables (Variables) supported by C#, and at times they are referred to as static variables and instance variables, respectively.

Um campo estático não é parte de uma instância específica; em vez disso, ele é compartilhado entre todas as instâncias de um tipo fechado (aberto e fechado tipos).A static field is not part of a specific instance; instead, it is shared amongst all instances of a closed type (Open and closed types). Não importa quantas instâncias de um tipo de classe fechados são criadas, há sempre apenas uma cópia de um campo estático para o domínio de aplicativo associado.No matter how many instances of a closed class type are created, there is only ever one copy of a static field for the associated application domain.

Por exemplo:For example:

class C<V>
{
    static int count = 0;

    public C() {
        count++;
    }

    public static int Count {
        get { return count; }
    }
}

class Application
{
    static void Main() {
        C<int> x1 = new C<int>();
        Console.WriteLine(C<int>.Count);        // Prints 1

        C<double> x2 = new C<double>();
        Console.WriteLine(C<int>.Count);        // Prints 1

        C<int> x3 = new C<int>();
        Console.WriteLine(C<int>.Count);        // Prints 2
    }
}

Um campo de instância pertence a uma instância.An instance field belongs to an instance. Especificamente, cada instância de uma classe contém um conjunto separado de todos os campos de instância dessa classe.Specifically, every instance of a class contains a separate set of all the instance fields of that class.

Quando um campo é referenciado em uma member_access (acesso de membro) do formulário E.M, se M é um campo estático, E deve indicar um tipo que contém M e se M é um campo de instância, E preciso marcar uma instância de um tipo que contém M.When a field is referenced in a member_access (Member access) of the form E.M, if M is a static field, E must denote a type containing M, and if M is an instance field, E must denote an instance of a type containing M.

As diferenças entre static e membros de instância são discutidos mais detalhadamente em membros estáticos e de instância.The differences between static and instance members are discussed further in Static and instance members.

Campos somente leituraReadonly fields

Quando um field_declaration inclui um readonly modificador, os campos apresentados pela declaração são campos somente leitura.When a field_declaration includes a readonly modifier, the fields introduced by the declaration are readonly fields. As atribuições diretas aos campos somente leitura só podem ocorrer como parte da declaração ou em um construtor de instância ou o construtor estático na mesma classe.Direct assignments to readonly fields can only occur as part of that declaration or in an instance constructor or static constructor in the same class. (Um campo somente leitura pode ser atribuído a várias vezes nesses contextos.) Especificamente, as atribuições diretas para um readonly campo são permitidos apenas nos seguintes contextos:(A readonly field can be assigned to multiple times in these contexts.) Specifically, direct assignments to a readonly field are permitted only in the following contexts:

  • No variable_declarator que apresenta o campo (incluindo um variable_initializer na declaração).In the variable_declarator that introduces the field (by including a variable_initializer in the declaration).
  • Para um campo de instância, nos construtores de instância da classe que contém a declaração de campo; para um campo estático, no construtor estático da classe que contém a declaração do campo.For an instance field, in the instance constructors of the class that contains the field declaration; for a static field, in the static constructor of the class that contains the field declaration. Eles também são os únicos contextos em que ele é válido para passar uma readonly campo como um out ou ref parâmetro.These are also the only contexts in which it is valid to pass a readonly field as an out or ref parameter.

A tentativa de atribuir a um readonly campo ou passá-lo como um out ou ref parâmetro em qualquer outro contexto é um erro de tempo de compilação.Attempting to assign to a readonly field or pass it as an out or ref parameter in any other context is a compile-time error.

Usando campos somente leitura estático para constantesUsing static readonly fields for constants

Um static readonly campo é útil quando um nome simbólico para um valor constante é desejado, mas quando o tipo do valor não é permitido em um const declaração, ou quando o valor não pode ser calculado em tempo de compilação.A static readonly field is useful when a symbolic name for a constant value is desired, but when the type of the value is not permitted in a const declaration, or when the value cannot be computed at compile-time. No exemploIn the example

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue = new Color(0, 0, 255);

    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

o Black, White, Red, Green, e Blue membros não podem ser declarados como const membros porque seus valores não podem ser computados em tempo de compilação.the Black, White, Red, Green, and Blue members cannot be declared as const members because their values cannot be computed at compile-time. No entanto, declará-las static readonly em vez disso, tem muito o mesmo efeito.However, declaring them static readonly instead has much the same effect.

Controle de versão de campos somente leitura estático e constantesVersioning of constants and static readonly fields

Constantes e campos somente leitura têm semântica de controle de versão de binários diferentes.Constants and readonly fields have different binary versioning semantics. Quando uma expressão fizer referência a uma constante, o valor da constante é obtido em tempo de compilação, mas quando uma expressão fizer referência a um campo somente leitura, o valor do campo não é obtido até o tempo de execução.When an expression references a constant, the value of the constant is obtained at compile-time, but when an expression references a readonly field, the value of the field is not obtained until run-time. Considere um aplicativo que consiste em dois programas separados:Consider an application that consists of two separate programs:

using System;

namespace Program1
{
    public class Utils
    {
        public static readonly int X = 1;
    }
}

namespace Program2
{
    class Test
    {
        static void Main() {
            Console.WriteLine(Program1.Utils.X);
        }
    }
}

O Program1 e Program2 namespaces denotam dois programas que são compilados separadamente.The Program1 and Program2 namespaces denote two programs that are compiled separately. Porque Program1.Utils.X é declarado como um campo somente leitura estático, a saída de valor a Console.WriteLine instrução não é conhecida no tempo de compilação, mas em vez disso, é obtida em tempo de execução.Because Program1.Utils.X is declared as a static readonly field, the value output by the Console.WriteLine statement is not known at compile-time, but rather is obtained at run-time. Portanto, se o valor de X é alterada e Program1 é recompilado, o Console.WriteLine instrução produzirá o novo valor, mesmo se Program2 não é recompilado.Thus, if the value of X is changed and Program1 is recompiled, the Console.WriteLine statement will output the new value even if Program2 isn't recompiled. No entanto, tinha X foi uma constante, o valor da X seria obtido no momento Program2 foi compilado e não seriam afetadas pelas alterações nos Program1 até que Program2 é recompilado.However, had X been a constant, the value of X would have been obtained at the time Program2 was compiled, and would remain unaffected by changes in Program1 until Program2 is recompiled.

Campos voláteisVolatile fields

Quando um field_declaration inclui um volatile são do modificador, os campos apresentados pela declaração campos voláteis.When a field_declaration includes a volatile modifier, the fields introduced by that declaration are volatile fields.

Para campos de não-volátil, técnicas de otimização que reorganizar as instruções podem levar a resultados inesperados e imprevisíveis em programas multithread que acessam campos sem sincronização como a fornecida pelo lock_statement (a instrução lock).For non-volatile fields, optimization techniques that reorder instructions can lead to unexpected and unpredictable results in multi-threaded programs that access fields without synchronization such as that provided by the lock_statement (The lock statement). Essas otimizações podem ser executadas pelo compilador, o sistema de tempo de execução ou hardware.These optimizations can be performed by the compiler, by the run-time system, or by hardware. Para os campos voláteis, essas otimizações de reordenação são restritas:For volatile fields, such reordering optimizations are restricted:

  • Uma leitura de um campo volátil é chamada um volátil de leitura.A read of a volatile field is called a volatile read. Uma leitura volátil tem "semântica de aquisição"; ou seja, é garantido que ele ocorrer antes de todas as referências a memória que ocorrem depois na sequência da instrução.A volatile read has "acquire semantics"; that is, it is guaranteed to occur prior to any references to memory that occur after it in the instruction sequence.
  • Uma gravação de um campo volátil é chamada de um escrita volátil.A write of a volatile field is called a volatile write. Uma escrita volátil tem "versão semântica"; ou seja, é garantido que ele ocorrer após todas as referências de memória antes da instrução de gravação na sequência da instrução.A volatile write has "release semantics"; that is, it is guaranteed to happen after any memory references prior to the write instruction in the instruction sequence.

Essas restrições garantem que todos os threads observem as gravações voláteis executadas por qualquer outro thread na ordem em que elas foram realizadas.These restrictions ensure that all threads will observe volatile writes performed by any other thread in the order in which they were performed. Uma implementação em conformidade não é necessário para fornecer uma ordenação total único de gravações voláteis como visto no todos os threads de execução.A conforming implementation is not required to provide a single total ordering of volatile writes as seen from all threads of execution. O tipo de um campo volátil deve ser um destes procedimentos:The type of a volatile field must be one of the following:

  • Um reference_type.A reference_type.
  • O tipo byte, sbyte, short, ushort, int, uint, char, float, bool, System.IntPtr, ou System.UIntPtr.The type byte, sbyte, short, ushort, int, uint, char, float, bool, System.IntPtr, or System.UIntPtr.
  • Uma enum_type tem um tipo de base de enumeração de byte, sbyte, short, ushort, int, ou uint.An enum_type having an enum base type of byte, sbyte, short, ushort, int, or uint.

O exemploThe example

using System;
using System.Threading;

class Test
{
    public static int result;   
    public static volatile bool finished;

    static void Thread2() {
        result = 143;    
        finished = true; 
    }

    static void Main() {
        finished = false;

        // Run Thread2() in a new thread
        new Thread(new ThreadStart(Thread2)).Start();

        // Wait for Thread2 to signal that it has a result by setting
        // finished to true.
        for (;;) {
            if (finished) {
                Console.WriteLine("result = {0}", result);
                return;
            }
        }
    }
}

produz a saída:produces the output:

result = 143

Neste exemplo, o método Main inicia um novo thread que executa o método Thread2.In this example, the method Main starts a new thread that runs the method Thread2. Este método armazena um valor em um campo não volátil denominado result, em seguida, armazena true no campo volátil finished.This method stores a value into a non-volatile field called result, then stores true in the volatile field finished. O thread principal aguarda o campo finished seja definida como true, em seguida, lê o campo result.The main thread waits for the field finished to be set to true, then reads the field result. Uma vez que finished tiver sido declarado volatile, o thread principal deve ler o valor 143 do campo result.Since finished has been declared volatile, the main thread must read the value 143 from the field result. Se o campo finished não tivessem sido declarados volatile, será permitido para o repositório para result fique visível para o thread principal após o armazenamento para finishede, portanto, para o thread principal ler o valor 0 do campo result.If the field finished had not been declared volatile, then it would be permissible for the store to result to be visible to the main thread after the store to finished, and hence for the main thread to read the value 0 from the field result. Declarando finished como um volatile campo impede que qualquer inconsistência tal.Declaring finished as a volatile field prevents any such inconsistency.

Inicialização do campoField initialization

O valor inicial de um campo, seja em um campo estático ou um campo de instância, é o valor padrão (valores padrão) do tipo do campo.The initial value of a field, whether it be a static field or an instance field, is the default value (Default values) of the field's type. Não é possível observar o valor de um campo antes dessa inicialização padrão tenha ocorrido e um campo, portanto, nunca é "não inicializado".It is not possible to observe the value of a field before this default initialization has occurred, and a field is thus never "uninitialized". O exemploThe example

using System;

class Test
{
    static bool b;
    int i;

    static void Main() {
        Test t = new Test();
        Console.WriteLine("b = {0}, i = {1}", b, t.i);
    }
}

produz a saídaproduces the output

b = False, i = 0

porque b e i são ambos inicializadas automaticamente para valores padrão.because b and i are both automatically initialized to default values.

Inicializadores de variávelVariable initializers

Declarações de campo podem incluir variable_initializers.Field declarations may include variable_initializers. Para campos estáticos, inicializadores de variável correspondem às instruções de atribuição que são executadas durante a inicialização de classe.For static fields, variable initializers correspond to assignment statements that are executed during class initialization. Por exemplo, campos de inicializadores de variável correspondem às instruções de atribuição que são executadas quando uma instância da classe é criada.For instance fields, variable initializers correspond to assignment statements that are executed when an instance of the class is created.

O exemploThe example

using System;

class Test
{
    static double x = Math.Sqrt(2.0);
    int i = 100;
    string s = "Hello";

    static void Main() {
        Test a = new Test();
        Console.WriteLine("x = {0}, i = {1}, s = {2}", x, a.i, a.s);
    }
}

produz a saídaproduces the output

x = 1.4142135623731, i = 100, s = Hello

porque uma atribuição para x ocorre quando executam os inicializadores de campo estático e as atribuições a i e s ocorrer ao executar os inicializadores de campo de instância.because an assignment to x occurs when static field initializers execute and assignments to i and s occur when the instance field initializers execute.

A inicialização de valor padrão descrita em inicialização do campo ocorre para todos os campos, incluindo os campos que têm inicializadores de variável.The default value initialization described in Field initialization occurs for all fields, including fields that have variable initializers. Assim, quando uma classe é inicializada, todos os campos estáticos nessa classe são inicializados pela primeira vez para seus valores padrão e, em seguida, os inicializadores de campo estático são executados na ordem textual.Thus, when a class is initialized, all static fields in that class are first initialized to their default values, and then the static field initializers are executed in textual order. Da mesma forma, quando uma instância de uma classe é criada, todos os campos de instância nessa instância são inicializados pela primeira vez para seus valores padrão e, em seguida, os inicializadores de campo de instância são executados na ordem textual.Likewise, when an instance of a class is created, all instance fields in that instance are first initialized to their default values, and then the instance field initializers are executed in textual order.

É possível para campos estáticos com inicializadores de variável a ser observado em seu estado de valor padrão.It is possible for static fields with variable initializers to be observed in their default value state. No entanto, isso é altamente desaconselhável como uma questão de estilo.However, this is strongly discouraged as a matter of style. O exemploThe example

using System;

class Test
{
    static int a = b + 1;
    static int b = a + 1;

    static void Main() {
        Console.WriteLine("a = {0}, b = {1}", a, b);
    }
}

exibir esse comportamento.exhibits this behavior. Apesar das definições circulares de um e b, o programa é válido.Despite the circular definitions of a and b, the program is valid. Isso resulta na saídaIt results in the output

a = 1, b = 2

porque os campos estáticos a e b são inicializadas como 0 (o valor padrão para int) antes de seus inicializadores são executados.because the static fields a and b are initialized to 0 (the default value for int) before their initializers are executed. Quando o inicializador para a é executado, o valor da b for zero e, portanto a é inicializado como 1.When the initializer for a runs, the value of b is zero, and so a is initialized to 1. Quando o inicializador para b é executado, o valor da a já está 1e, portanto b é inicializado como 2.When the initializer for b runs, the value of a is already 1, and so b is initialized to 2.

Inicialização do campo estáticoStatic field initialization

Os inicializadores de variável de campo estático de uma classe correspondem a uma sequência de atribuições que são executados na ordem textual em que aparecem na declaração da classe.The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration. Se um construtor estático (construtores estáticos) existe na classe, a execução de inicializadores de campo estático ocorre imediatamente antes de executar esse construtor estático.If a static constructor (Static constructors) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Caso contrário, os inicializadores de campo estático são executados em um momento dependente da implementação antes do primeiro uso de um campo estático da classe.Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class. O exemploThe example

using System;

class Test 
{ 
    static void Main() {
        Console.WriteLine("{0} {1}", B.Y, A.X);
    }

    public static int F(string s) {
        Console.WriteLine(s);
        return 1;
    }
}

class A
{
    public static int X = Test.F("Init A");
}

class B
{
    public static int Y = Test.F("Init B");
}

pode produzir a saída:might produce either the output:

Init A
Init B
1 1

ou a saída:or the output:

Init B
Init A
1 1

porque a execução de Xdo inicializador e Ydo inicializador pode ocorrer em qualquer ordem; eles apenas são restritos a ocorrer antes das referências a esses campos.because the execution of X's initializer and Y's initializer could occur in either order; they are only constrained to occur before the references to those fields. No entanto, no exemplo:However, in the example:

using System;

class Test
{
    static void Main() {
        Console.WriteLine("{0} {1}", B.Y, A.X);
    }

    public static int F(string s) {
        Console.WriteLine(s);
        return 1;
    }
}

class A
{
    static A() {}

    public static int X = Test.F("Init A");
}

class B
{
    static B() {}

    public static int Y = Test.F("Init B");
}

a saída deve ser:the output must be:

Init B
Init A
1 1

porque as regras para quando executam os construtores estáticos (conforme definido em construtores estáticos) fornecê-lo Bdo construtor estático (e, portanto, Bdo inicializadores de campo estático) deve ser executado antes Ado construtor estático e inicializadores de campo.because the rules for when static constructors execute (as defined in Static constructors) provide that B's static constructor (and hence B's static field initializers) must run before A's static constructor and field initializers.

Inicialização do campo de instânciaInstance field initialization

Os inicializadores de variável de campo de instância de uma classe correspondem a uma sequência de atribuições que são executados imediatamente após a entrada para qualquer um dos construtores de instância (inicializadores de construtor) dessa classe.The instance field variable initializers of a class correspond to a sequence of assignments that are executed immediately upon entry to any one of the instance constructors (Constructor initializers) of that class. Os inicializadores de variável são executados na ordem textual em que aparecem na declaração da classe.The variable initializers are executed in the textual order in which they appear in the class declaration. O processo de criação e a inicialização da instância classe é descrito posteriormente em construtores de instância.The class instance creation and initialization process is described further in Instance constructors.

Um inicializador de variável para um campo de instância não pode referenciar a instância que está sendo criada.A variable initializer for an instance field cannot reference the instance being created. Portanto, é um erro de tempo de compilação para fazer referência a this em um inicializador de variável, pois ele é um erro de tempo de compilação para um inicializador de variável fazer referência a qualquer membro de instância por meio de um simple_name.Thus, it is a compile-time error to reference this in a variable initializer, as it is a compile-time error for a variable initializer to reference any instance member through a simple_name. No exemploIn the example

class A
{
    int x = 1;
    int y = x + 1;        // Error, reference to instance member of this
}

o inicializador de variável de y resulta em um erro de tempo de compilação, pois ela faz referência a um membro da instância que está sendo criado.the variable initializer for y results in a compile-time error because it references a member of the instance being created.

MétodosMethods

Um método é um membro que implementa um cálculo ou uma ação que pode ser executada por um objeto ou classe.A method is a member that implements a computation or action that can be performed by an object or class. Os métodos são declarados usando method_declarations:Methods are declared using method_declarations:

method_declaration
    : method_header method_body
    ;

method_header
    : attributes? method_modifier* 'partial'? return_type member_name type_parameter_list?
      '(' formal_parameter_list? ')' type_parameter_constraints_clause*
    ;

method_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | 'async'
    | method_modifier_unsafe
    ;

return_type
    : type
    | 'void'
    ;

member_name
    : identifier
    | interface_type '.' identifier
    ;

method_body
    : block
    | '=>' expression ';'
    | ';'
    ;

Um method_declaration pode incluir um conjunto de atributos (atributos) e uma combinação válida de as quatro modificadores de acesso (modificadores de acesso ), o new (o novo modificador), static (métodos estáticos e de instância), virtual (métodos virtuais), override (Substituir métodos), sealed (lacrados métodos), abstract (métodos abstratos), e extern (Métodos externos) modificadores.A method_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), static (Static and instance methods), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

Uma declaração tem uma combinação válida dos modificadores se todos os itens a seguir forem verdadeiras:A declaration has a valid combination of modifiers if all of the following are true:

  • A declaração inclui uma combinação válida de modificadores de acesso (modificadores de acesso).The declaration includes a valid combination of access modifiers (Access modifiers).
  • A declaração não inclui o mesmo modificador várias vezes.The declaration does not include the same modifier multiple times.
  • A declaração inclui no máximo um dos modificadores a seguir: static, virtual, e override.The declaration includes at most one of the following modifiers: static, virtual, and override.
  • A declaração inclui no máximo um dos modificadores a seguir: new e override.The declaration includes at most one of the following modifiers: new and override.
  • Se a declaração inclui o abstract modificador e, em seguida, a declaração não inclui nenhum dos modificadores a seguir: static, virtual, sealed ou extern.If the declaration includes the abstract modifier, then the declaration does not include any of the following modifiers: static, virtual, sealed or extern.
  • Se a declaração inclui o private modificador e, em seguida, a declaração não inclui nenhum dos modificadores a seguir: virtual, override, ou abstract.If the declaration includes the private modifier, then the declaration does not include any of the following modifiers: virtual, override, or abstract.
  • Se a declaração inclui o sealed modificador e, em seguida, a declaração também inclui o override modificador.If the declaration includes the sealed modifier, then the declaration also includes the override modifier.
  • Se a declaração inclui o partial modificador, em seguida, ele não inclui nenhum dos modificadores a seguir: new, public, protected, internal, private, virtual, sealed, override , abstract, ou extern.If the declaration includes the partial modifier, then it does not include any of the following modifiers: new, public, protected, internal, private, virtual, sealed, override, abstract, or extern.

Um método que tem o async modificador é uma função assíncrona e segue as regras descritas em funções assíncronas.A method that has the async modifier is an async function and follows the rules described in Async functions.

O return_type de um método de declaração especifica o tipo de valor calculado e retornado pelo método.The return_type of a method declaration specifies the type of the value computed and returned by the method. O return_type é void se o método não retorna um valor.The return_type is void if the method does not return a value. Se a declaração inclui o partial modificador e, em seguida, o tipo de retorno deve ser void.If the declaration includes the partial modifier, then the return type must be void.

O member_name Especifica o nome do método.The member_name specifies the name of the method. A menos que o método é uma implementação de membro de interface explícita (implementações de membros de interface explícita), o member_name é simplesmente uma identificador.Unless the method is an explicit interface member implementation (Explicit interface member implementations), the member_name is simply an identifier. Para uma implementação de membro de interface explícita, o member_name consiste em um interface_type seguido por um "." e uma identificador.For an explicit interface member implementation, the member_name consists of an interface_type followed by a "." and an identifier.

Opcional type_parameter_list Especifica os parâmetros de tipo do método (parâmetros de tipo).The optional type_parameter_list specifies the type parameters of the method (Type parameters). Se um type_parameter_list for especificado o método é um método genérico.If a type_parameter_list is specified the method is a generic method. Se o método tem um extern modificador, uma type_parameter_list não pode ser especificado.If the method has an extern modifier, a type_parameter_list cannot be specified.

Opcional formal_parameter_list Especifica os parâmetros do método (parâmetros de método).The optional formal_parameter_list specifies the parameters of the method (Method parameters).

Opcional type_parameter_constraints_clauses especificar restrições em parâmetros de tipo individuais (restrições de parâmetro de tipo) e só pode ser especificada se uma type_parameter_ lista também for fornecido, e o método não tem um override modificador.The optional type_parameter_constraints_clauses specify constraints on individual type parameters (Type parameter constraints) and may only be specified if a type_parameter_list is also supplied, and the method does not have an override modifier.

O return_type e cada um dos tipos referenciados nas formal_parameter_list de um método deve ser pelo menos tão acessíveis quanto o próprio método (restrições de acessibilidade).The return_type and each of the types referenced in the formal_parameter_list of a method must be at least as accessible as the method itself (Accessibility constraints).

O method_body é um vírgula, um corpo da instrução ou uma corpo da expressão.The method_body is either a semicolon, a statement body or an expression body. Um corpo de declaração consiste em uma bloco, que especifica as instruções para executar quando o método é invocado.A statement body consists of a block, which specifies the statements to execute when the method is invoked. Consiste em um corpo de expressão => seguido por um expressão e um ponto e vírgula e denota uma única expressão para executar quando o método é invocado.An expression body consists of => followed by an expression and a semicolon, and denotes a single expression to perform when the method is invoked.

Para abstract e extern métodos, o method_body consiste simplesmente em um ponto e vírgula.For abstract and extern methods, the method_body consists simply of a semicolon. Para partial métodos de method_body pode consistir em um ponto e vírgula, um corpo do bloco ou um corpo de expressão.For partial methods the method_body may consist of either a semicolon, a block body or an expression body. Para todos os outros métodos, o method_body é um corpo do bloco ou um corpo de expressão.For all other methods, the method_body is either a block body or an expression body.

Se o method_body consiste em um ponto e vírgula, em seguida, a declaração não pode incluir o async modificador.If the method_body consists of a semicolon, then the declaration may not include the async modifier.

O nome, a lista de parâmetros de tipo e a lista de parâmetros formais de um método de definem a assinatura (assinaturas e sobrecarga) do método.The name, the type parameter list and the formal parameter list of a method define the signature (Signatures and overloading) of the method. Especificamente, a assinatura de um método consiste em seu nome, o número de parâmetros de tipo e o número, modificadores e tipos de seus parâmetros formais.Specifically, the signature of a method consists of its name, the number of type parameters and the number, modifiers, and types of its formal parameters. Para esses fins, qualquer parâmetro de tipo do método que ocorre no tipo de um parâmetro formal é identificado, não por seu nome, mas, por sua posição ordinal na lista de argumentos de tipo do método. O tipo de retorno não é parte da assinatura do método, nem é os nomes dos parâmetros de tipo ou os parâmetros formais.For these purposes, any type parameter of the method that occurs in the type of a formal parameter is identified not by its name, but by its ordinal position in the type argument list of the method.The return type is not part of a method's signature, nor are the names of the type parameters or the formal parameters.

O nome de um método deve ser diferente dos nomes de todos os outros não-métodos declarados na mesma classe.The name of a method must differ from the names of all other non-methods declared in the same class. Além disso, a assinatura de um método deve ser diferente das assinaturas de todos os outros métodos declarados na mesma classe, e dois métodos declarados na mesma classe não podem ter assinaturas que diferem somente por ref e out.In addition, the signature of a method must differ from the signatures of all other methods declared in the same class, and two methods declared in the same class may not have signatures that differ solely by ref and out.

O método type_parameters estão no escopo em todo o method_declaratione pode ser usado para tipos de formulário em todo o escopo no return_type, method_body, e type_parameter_constraints_clauses, mas não no atributos.The method's type_parameters are in scope throughout the method_declaration, and can be used to form types throughout that scope in return_type, method_body, and type_parameter_constraints_clauses but not in attributes.

Todos os parâmetros de tipo e parâmetros formais devem ter nomes diferentes.All formal parameters and type parameters must have different names.

Parâmetros de métodoMethod parameters

Os parâmetros de um método, se houver, são declarados pelo método formal_parameter_list.The parameters of a method, if any, are declared by the method's formal_parameter_list.

formal_parameter_list
    : fixed_parameters
    | fixed_parameters ',' parameter_array
    | parameter_array
    ;

fixed_parameters
    : fixed_parameter (',' fixed_parameter)*
    ;

fixed_parameter
    : attributes? parameter_modifier? type identifier default_argument?
    ;

default_argument
    : '=' expression
    ;

parameter_modifier
    : 'ref'
    | 'out'
    | 'this'
    ;

parameter_array
    : attributes? 'params' array_type identifier
    ;

A lista de parâmetros formal consiste em um ou mais parâmetros separados por vírgulas dos quais apenas a última pode ser um parameter_array.The formal parameter list consists of one or more comma-separated parameters of which only the last may be a parameter_array.

Um fixed_parameter consiste em um conjunto opcional de atributos (atributos), um recurso opcional ref, out ou this modificador, um tipo, um identificador e um opcional default_argument.A fixed_parameter consists of an optional set of attributes (Attributes), an optional ref, out or this modifier, a type, an identifier and an optional default_argument. Cada fixed_parameter declara um parâmetro do tipo especificado com o nome fornecido.Each fixed_parameter declares a parameter of the given type with the given name. O this modificador designa o método como um método de extensão e só é permitido no primeiro parâmetro de um método estático.The this modifier designates the method as an extension method and is only allowed on the first parameter of a static method. Métodos de extensão são descritos na métodos de extensão.Extension methods are further described in Extension methods.

Um fixed_parameter com um default_argument é conhecido como um parâmetro opcional, enquanto uma fixed_parameter sem um default_argument é um parâmetro necessário.A fixed_parameter with a default_argument is known as an optional parameter, whereas a fixed_parameter without a default_argument is a required parameter. Um parâmetro obrigatório não pode aparecer após um parâmetro opcional em uma formal_parameter_list.A required parameter may not appear after an optional parameter in a formal_parameter_list.

Um ref ou out parâmetro não pode ter um default_argument.A ref or out parameter cannot have a default_argument. O expressão em um default_argument deve ser um dos seguintes:The expression in a default_argument must be one of the following:

  • a constant_expressiona constant_expression
  • uma expressão do formulário new S() onde S é um tipo de valoran expression of the form new S() where S is a value type
  • uma expressão do formulário default(S) onde S é um tipo de valoran expression of the form default(S) where S is a value type

O expressão deve ser implicitamente conversível por uma identidade ou uma conversão que permitem valor nulo para o tipo do parâmetro.The expression must be implicitly convertible by an identity or nullable conversion to the type of the parameter.

Se os parâmetros opcionais ocorrem em uma declaração de método parcial de implementação (métodos parciais), uma implementação de membro de interface explícita (implementações de membros de interface explícita) ou em um declaração de indexador único parâmetro (indexadores) o compilador deve fornecer um aviso, pois esses membros nunca podem ser invocados de forma que permite que os argumentos a serem omitidos.If optional parameters occur in an implementing partial method declaration (Partial methods) , an explicit interface member implementation (Explicit interface member implementations) or in a single-parameter indexer declaration (Indexers) the compiler should give a warning, since these members can never be invoked in a way that permits arguments to be omitted.

Um parameter_array consiste em um conjunto opcional de atributos (atributos), um params modificador, um array_type, e um identificador.A parameter_array consists of an optional set of attributes (Attributes), a params modifier, an array_type, and an identifier. Uma matriz de parâmetros declara um único parâmetro do tipo matriz fornecida com o nome fornecido.A parameter array declares a single parameter of the given array type with the given name. O array_type de um parâmetro de matriz deve ser um tipo de matriz unidimensional (tipos de matriz).The array_type of a parameter array must be a single-dimensional array type (Array types). Em uma invocação de método, uma matriz de parâmetro permite que um único argumento do tipo de matriz especificada a ser especificado ou permite a zero ou mais argumentos do tipo de elemento de matriz sejam especificados.In a method invocation, a parameter array permits either a single argument of the given array type to be specified, or it permits zero or more arguments of the array element type to be specified. Matrizes de parâmetros são descritos mais detalhadamente em matrizes de parâmetro.Parameter arrays are described further in Parameter arrays.

Um parameter_array pode ocorrer após um parâmetro opcional, mas não pode ter um valor padrão – a omissão de argumentos para um parameter_array resultaria em vez disso, a criação de uma matriz vazia.A parameter_array may occur after an optional parameter, but cannot have a default value -- the omission of arguments for a parameter_array would instead result in the creation of an empty array.

O exemplo a seguir ilustra os diferentes tipos de parâmetros:The following example illustrates different kinds of parameters:

public void M(
    ref int      i,
    decimal      d,
    bool         b = false,
    bool?        n = false,
    string       s = "Hello",
    object       o = null,
    T            t = default(T),
    params int[] a
) { }

No formal_parameter_list para M, i é um parâmetro ref necessária, d é um parâmetro de valor necessário b, s, o e t parâmetros de valor opcional e a é uma matriz de parâmetros.In the formal_parameter_list for M, i is a required ref parameter, d is a required value parameter, b, s, o and t are optional value parameters and a is a parameter array.

Uma declaração de método cria um espaço de declaração separada para parâmetros, parâmetros de tipo e variáveis locais.A method declaration creates a separate declaration space for parameters, type parameters and local variables. Nomes são apresentados nesse espaço de declaração, a lista de parâmetros de tipo e a lista de parâmetros formais do método e por declarações de variável local na bloco do método.Names are introduced into this declaration space by the type parameter list and the formal parameter list of the method and by local variable declarations in the block of the method. É um erro para dois membros de um espaço de declaração de método ter o mesmo nome.It is an error for two members of a method declaration space to have the same name. É um erro para o espaço de declaração de método e o espaço de declaração de variável local de um espaço de declaração aninhadas para conter elementos com o mesmo nome.It is an error for the method declaration space and the local variable declaration space of a nested declaration space to contain elements with the same name.

Uma invocação de método (invocações de método) cria uma cópia específica para essa invocação, de parâmetros formais e variáveis locais do método e lista de argumentos de invocação atribui valores ou referências de variável para o recém-criados parâmetros formais.A method invocation (Method invocations) creates a copy, specific to that invocation, of the formal parameters and local variables of the method, and the argument list of the invocation assigns values or variable references to the newly created formal parameters. Dentro de bloco de um método, os parâmetros formais podem ser referenciados por seus identificadores na simple_name expressões (nomes simples).Within the block of a method, formal parameters can be referenced by their identifiers in simple_name expressions (Simple names).

Há quatro tipos de parâmetros formais:There are four kinds of formal parameters:

  • Parâmetros de valor, que são declarados sem qualquer modificador.Value parameters, which are declared without any modifiers.
  • Fazer referência a parâmetros, que são declarados com o ref modificador.Reference parameters, which are declared with the ref modifier.
  • Parâmetros de saída, que são declarados com o out modificador.Output parameters, which are declared with the out modifier.
  • Matrizes de parâmetros que são declarados com o params modificador.Parameter arrays, which are declared with the params modifier.

Conforme descrito em assinaturas e sobrecarga, o ref e out modificadores fazem parte da assinatura do método, mas o params modificador não é.As described in Signatures and overloading, the ref and out modifiers are part of a method's signature, but the params modifier is not.

Parâmetros de valorValue parameters

Um parâmetro declarado com nenhum modificador é um parâmetro de valor.A parameter declared with no modifiers is a value parameter. Um parâmetro de valor corresponde a uma variável local que obtém seu valor inicial do argumento correspondente fornecido na invocação de método.A value parameter corresponds to a local variable that gets its initial value from the corresponding argument supplied in the method invocation.

Quando um parâmetro formal é um parâmetro de valor, o argumento correspondente em uma invocação de método deve ser uma expressão que é implicitamente conversível (conversões implícitas) para o tipo de parâmetro formal.When a formal parameter is a value parameter, the corresponding argument in a method invocation must be an expression that is implicitly convertible (Implicit conversions) to the formal parameter type.

Um método tem permissão para atribuir novos valores para um parâmetro de valor.A method is permitted to assign new values to a value parameter. Essas atribuições afetam apenas o local de armazenamento local representado pelo parâmetro de valor — eles não têm efeito sobre o argumento real fornecido na invocação do método.Such assignments only affect the local storage location represented by the value parameter—they have no effect on the actual argument given in the method invocation.

Parâmetros de referênciaReference parameters

Um parâmetro declarado com um ref modificador é um parâmetro de referência.A parameter declared with a ref modifier is a reference parameter. Ao contrário de um parâmetro de valor, um parâmetro de referência não cria um novo local de armazenamento.Unlike a value parameter, a reference parameter does not create a new storage location. Em vez disso, um parâmetro de referência representa o mesmo local de armazenamento como a variável fornecido como o argumento na invocação de método.Instead, a reference parameter represents the same storage location as the variable given as the argument in the method invocation.

Quando um parâmetro formal é um parâmetro de referência, o argumento correspondente em uma invocação de método deve conter a palavra-chave ref seguido por um variable_reference (precisas regras para determinar atribuição definitiva) do mesmo tipo que o parâmetro formal.When a formal parameter is a reference parameter, the corresponding argument in a method invocation must consist of the keyword ref followed by a variable_reference (Precise rules for determining definite assignment) of the same type as the formal parameter. Uma variável deve ser definitivamente atribuída antes que ele pode ser passado como um parâmetro de referência.A variable must be definitely assigned before it can be passed as a reference parameter.

Dentro de um método, um parâmetro de referência é sempre considerado atribuído definitivamente.Within a method, a reference parameter is always considered definitely assigned.

Um método declarado como um iterador (iteradores) não pode ter parâmetros de referência.A method declared as an iterator (Iterators) cannot have reference parameters.

O exemploThe example

using System;

class Test
{
    static void Swap(ref int x, ref int y) {
        int temp = x;
        x = y;
        y = temp;
    }

    static void Main() {
        int i = 1, j = 2;
        Swap(ref i, ref j);
        Console.WriteLine("i = {0}, j = {1}", i, j);
    }
}

produz a saídaproduces the output

i = 2, j = 1

Para a invocação dos Swap na Main, x representa i e y representa j.For the invocation of Swap in Main, x represents i and y represents j. Portanto, a invocação tem o efeito de troca os valores das i e j.Thus, the invocation has the effect of swapping the values of i and j.

Em um método que usa parâmetros de referência, é possível que vários nomes representar o mesmo local de armazenamento.In a method that takes reference parameters it is possible for multiple names to represent the same storage location. No exemploIn the example

class A
{
    string s;

    void F(ref string a, ref string b) {
        s = "One";
        a = "Two";
        b = "Three";
    }

    void G() {
        F(ref s, ref s);
    }
}

a invocação de F na G passa uma referência a s para ambos a e b.the invocation of F in G passes a reference to s for both a and b. Assim, para essa invocação, os nomes s, a, e b todas se referem ao mesmo local de armazenamento e as todas as atribuições de três modificar o campo de instância s.Thus, for that invocation, the names s, a, and b all refer to the same storage location, and the three assignments all modify the instance field s.

Parâmetros de saídaOutput parameters

Um parâmetro declarado com um out modificador é um parâmetro de saída.A parameter declared with an out modifier is an output parameter. Semelhante a um parâmetro de referência, um parâmetro de saída não cria um novo local de armazenamento.Similar to a reference parameter, an output parameter does not create a new storage location. Em vez disso, um parâmetro de saída representa o mesmo local de armazenamento como a variável fornecido como o argumento na invocação de método.Instead, an output parameter represents the same storage location as the variable given as the argument in the method invocation.

Quando um parâmetro formal é um parâmetro de saída, o argumento correspondente em uma invocação de método deve conter a palavra-chave out seguido por um variable_reference (precisas regras para determinar atribuição definitiva) do mesmo tipo que o parâmetro formal.When a formal parameter is an output parameter, the corresponding argument in a method invocation must consist of the keyword out followed by a variable_reference (Precise rules for determining definite assignment) of the same type as the formal parameter. Uma variável não precisa ser definitivamente atribuída antes que ela pode ser passada como um parâmetro output, mas após uma invocação em que uma variável foi passada como um parâmetro de saída, a variável é considerada atribuída definitivamente.A variable need not be definitely assigned before it can be passed as an output parameter, but following an invocation where a variable was passed as an output parameter, the variable is considered definitely assigned.

Dentro de um método, assim como um local variável, um parâmetro de saída é inicialmente considerado não atribuídos e deve ser definitivamente atribuído antes que seu valor é usado.Within a method, just like a local variable, an output parameter is initially considered unassigned and must be definitely assigned before its value is used.

Cada parâmetro de saída de um método deve ser definitivamente atribuído antes que o método retorna.Every output parameter of a method must be definitely assigned before the method returns.

Um método declarado como um método parcial (métodos parciais) ou um iterador (iteradores) não pode ter parâmetros de saída.A method declared as a partial method (Partial methods) or an iterator (Iterators) cannot have output parameters.

Parâmetros de saída normalmente são usados em métodos que produzem vários valores de retorno.Output parameters are typically used in methods that produce multiple return values. Por exemplo:For example:

using System;

class Test
{
    static void SplitPath(string path, out string dir, out string name) {
        int i = path.Length;
        while (i > 0) {
            char ch = path[i - 1];
            if (ch == '\\' || ch == '/' || ch == ':') break;
            i--;
        }
        dir = path.Substring(0, i);
        name = path.Substring(i);
    }

    static void Main() {
        string dir, name;
        SplitPath("c:\\Windows\\System\\hello.txt", out dir, out name);
        Console.WriteLine(dir);
        Console.WriteLine(name);
    }
}

O exemplo produz a saída:The example produces the output:

c:\Windows\System\
hello.txt

Observe que o dir e name variáveis podem ser atribuídas antes de serem passados para SplitPath, e eles são considerados definitivamente atribuídos após a chamada.Note that the dir and name variables can be unassigned before they are passed to SplitPath, and that they are considered definitely assigned following the call.

Matrizes de parâmetrosParameter arrays

Um parâmetro declarado com um params modificador é uma matriz de parâmetros.A parameter declared with a params modifier is a parameter array. Se uma lista de parâmetros formal inclui uma matriz de parâmetros, ele deve ser o último parâmetro na lista e ele deve ser de um tipo de matriz unidimensional.If a formal parameter list includes a parameter array, it must be the last parameter in the list and it must be of a single-dimensional array type. Por exemplo, os tipos string[] e string[][] pode ser usado como o tipo de uma matriz de parâmetros, mas o tipo string[,] não pode.For example, the types string[] and string[][] can be used as the type of a parameter array, but the type string[,] can not. Não é possível combinar as params modificador com os modificadores ref e out.It is not possible to combine the params modifier with the modifiers ref and out.

Uma matriz de parâmetro permite que os argumentos a ser especificada em uma das duas maneiras de uma invocação de método:A parameter array permits arguments to be specified in one of two ways in a method invocation:

  • O argumento fornecido para uma matriz de parâmetros pode ser uma única expressão que é implicitamente conversível (conversões implícitas) para o tipo de matriz de parâmetro.The argument given for a parameter array can be a single expression that is implicitly convertible (Implicit conversions) to the parameter array type. Nesse caso, a matriz de parâmetro Age exatamente como um parâmetro de valor.In this case, the parameter array acts precisely like a value parameter.
  • Como alternativa, a invocação pode especificar zero ou mais argumentos para a matriz de parâmetros, onde cada argumento é uma expressão que é implicitamente conversível (conversões implícitas) para o tipo de elemento da matriz de parâmetros.Alternatively, the invocation can specify zero or more 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. Nesse caso, a invocação cria uma instância do tipo de parâmetro de matriz com um comprimento correspondente ao número de argumentos, inicializa os elementos da instância de matriz com os valores de argumento fornecido e usa a instância de matriz recém-criado como o real argumento.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.

Exceto para permitir que um número variável de argumentos em uma invocação, uma matriz de parâmetros é precisamente equivalente a um parâmetro de valor (parâmetros de valores) do mesmo tipo.Except for allowing a variable number of arguments in an invocation, a parameter array is precisely equivalent to a value parameter (Value parameters) of the same type.

O exemploThe example

using System;

class Test
{
    static void F(params int[] args) {
        Console.Write("Array contains {0} elements:", args.Length);
        foreach (int i in args) 
            Console.Write(" {0}", i);
        Console.WriteLine();
    }

    static void Main() {
        int[] arr = {1, 2, 3};
        F(arr);
        F(10, 20, 30, 40);
        F();
    }
}

produz a saídaproduces the output

Array contains 3 elements: 1 2 3
Array contains 4 elements: 10 20 30 40
Array contains 0 elements:

A primeira invocação da F simplesmente passa a matriz a como um parâmetro de valor.The first invocation of F simply passes the array a as a value parameter. A segunda chamada de F cria automaticamente os quatro elementos int[] com os valores do elemento fornecido e passa esse instância como um parâmetro de valor de matriz.The second invocation of F automatically creates a four-element int[] with the given element values and passes that array instance as a value parameter. Da mesma forma, a terceira invocação de F cria um elemento de zero int[] e passa essa instância como um parâmetro de valor.Likewise, the third invocation of F creates a zero-element int[] and passes that instance as a value parameter. As invocações de segunda e terceira são precisamente equivalentes a gravação:The second and third invocations are precisely equivalent to writing:

F(new int[] {10, 20, 30, 40});
F(new int[] {});

Ao executar a resolução de sobrecarga, um método com uma matriz de parâmetros pode ser aplicável em sua forma normal ou em sua forma expandida (membro da função aplicável).When performing overload resolution, a method with a parameter array may be applicable either in its normal form or in its expanded form (Applicable function member). A forma expandida de um método está disponível somente se o formulário normal do método não é aplicável e somente se um método aplicável com a mesma assinatura que a forma expandida já não está declarado no mesmo tipo.The expanded form of a method is available only if the normal form of the method is not applicable and only if an applicable method with the same signature as the expanded form is not already declared in the same type.

O exemploThe example

using System;

class Test
{
    static void F(params object[] a) {
        Console.WriteLine("F(object[])");
    }

    static void F() {
        Console.WriteLine("F()");
    }

    static void F(object a0, object a1) {
        Console.WriteLine("F(object,object)");
    }

    static void Main() {
        F();
        F(1);
        F(1, 2);
        F(1, 2, 3);
        F(1, 2, 3, 4);
    }
}

produz a saídaproduces the output

F();
F(object[]);
F(object,object);
F(object[]);
F(object[]);

No exemplo, duas das formas possíveis expandidas do método com uma matriz de parâmetros já estão incluídas na classe como métodos regulares.In the example, two of the possible expanded forms of the method with a parameter array are already included in the class as regular methods. Esses formulários expandidos, portanto, são considerados não ao executar a resolução de sobrecarga e das invocações de método primeiro e terceiro, portanto, selecione os métodos regulares.These expanded forms are therefore not considered when performing overload resolution, and the first and third method invocations thus select the regular methods. Quando uma classe declara um método com uma matriz de parâmetros, não é incomum para incluir também algumas das formas expandidas como métodos regulares.When a class declares a method with a parameter array, it is not uncommon to also include some of the expanded forms as regular methods. Ao fazer isso, é possível evitar a alocação de uma matriz a instância que ocorre quando uma forma expandida de um método com uma matriz de parâmetros é invocada.By doing so it is possible to avoid the allocation of an array instance that occurs when an expanded form of a method with a parameter array is invoked.

Quando o tipo de uma matriz de parâmetros é object[], uma ambiguidade potencial surge entre o formulário normal do método e o formulário expended para um único object parâmetro.When the type of a parameter array is object[], a potential ambiguity arises between the normal form of the method and the expended form for a single object parameter. O motivo para a ambiguidade é que um object[] é implicitamente conversível para o tipo object.The reason for the ambiguity is that an object[] is itself implicitly convertible to type object. A ambiguidade não apresenta nenhum problema, no entanto, uma vez que ele pode ser resolvido com a inserção de uma conversão se necessário.The ambiguity presents no problem, however, since it can be resolved by inserting a cast if needed.

O exemploThe example

using System;

class Test
{
    static void F(params object[] args) {
        foreach (object o in args) {
            Console.Write(o.GetType().FullName);
            Console.Write(" ");
        }
        Console.WriteLine();
    }

    static void Main() {
        object[] a = {1, "Hello", 123.456};
        object o = a;
        F(a);
        F((object)a);
        F(o);
        F((object[])o);
    }
}

produz a saídaproduces the output

System.Int32 System.String System.Double
System.Object[]
System.Object[]
System.Int32 System.String System.Double

Nas invocações primeiros e últimas do F, a forma normal de F é aplicável porque existe uma conversão implícita do tipo de argumento para o tipo de parâmetro (ambos são do tipo object[]).In the first and last invocations of F, the normal form of F is applicable because an implicit conversion exists from the argument type to the parameter type (both are of type object[]). Portanto, a resolução de sobrecarga seleciona a forma normal de F, e o argumento é passado como um parâmetro de valor comum.Thus, overload resolution selects the normal form of F, and the argument is passed as a regular value parameter. Em que as invocações de segunda e terceira, a forma normal de F não é aplicável porque não existe de nenhuma conversão implícita do tipo de argumento para o tipo de parâmetro (tipo object não pode ser implicitamente convertido no tipo object[]).In the second and third invocations, the normal form of F is not applicable because no implicit conversion exists from the argument type to the parameter type (type object cannot be implicitly converted to type object[]). No entanto, a forma expandida do F é aplicável, portanto, é selecionada por resolução de sobrecarga.However, the expanded form of F is applicable, so it is selected by overload resolution. Como resultado, um elemento object[] é criado por meio da chamada, e o único elemento da matriz é inicializado com o valor do argumento fornecido (que por si só é uma referência a um object[]).As a result, a one-element object[] is created by the invocation, and the single element of the array is initialized with the given argument value (which itself is a reference to an object[]).

Métodos estáticos e de instânciaStatic and instance methods

Quando uma declaração de método inclui um static modificador, que o método deve ser um método estático.When a method declaration includes a static modifier, that method is said to be a static method. Quando nenhum static modificador estiver presente, o método deve ser um método de instância.When no static modifier is present, the method is said to be an instance method.

Um método estático não funciona em uma instância específica e é um erro de tempo de compilação para se referir a this em um método estático.A static method does not operate on a specific instance, and it is a compile-time error to refer to this in a static method.

Um método de instância opera em uma determinada instância de uma classe, e essa instância pode ser acessada como this (esse acesso).An instance method operates on a given instance of a class, and that instance can be accessed as this (This access).

Quando um método é referenciado em uma member_access (acesso de membro) do formulário E.M, se M é um método estático, E deve indicar um tipo que contém Me se M é um método de instância E preciso marcar uma instância de um tipo que contém M.When a method is referenced in a member_access (Member access) of the form E.M, if M is a static method, E must denote a type containing M, and if M is an instance method, E must denote an instance of a type containing M.

As diferenças entre static e membros de instância são discutidos mais detalhadamente em membros estáticos e de instância.The differences between static and instance members are discussed further in Static and instance members.

Métodos virtuaisVirtual methods

Quando uma declaração de método de instância inclui um virtual modificador, que o método deve ser um método virtual.When an instance method declaration includes a virtual modifier, that method is said to be a virtual method. Quando nenhum virtual modificador estiver presente, o método deve ser um método não virtual.When no virtual modifier is present, the method is said to be a non-virtual method.

A implementação de um método não virtual é invariável: A implementação é o mesmo se o método é invocado em uma instância da classe na qual ele é declarado ou uma instância de uma classe derivada.The implementation of a non-virtual method is invariant: The implementation is the same whether the method is invoked on an instance of the class in which it is declared or an instance of a derived class. Por outro lado, a implementação de um método virtual pode ser substituída por classes derivadas.In contrast, the implementation of a virtual method can be superseded by derived classes. O processo de substituição a implementação de um método virtual herdado é conhecido como substituindo método (substituir métodos).The process of superseding the implementation of an inherited virtual method is known as overriding that method (Override methods).

Em uma invocação de método virtual, o tipo de tempo de execução da instância para o qual usa essa invocação ocorre determina a implementação real do método para invocar.In a virtual method invocation, the run-time type of the instance for which that invocation takes place determines the actual method implementation to invoke. Em uma invocação de método não virtual, o tipo de tempo de compilação da instância é o fator determinante.In a non-virtual method invocation, the compile-time type of the instance is the determining factor. Em termos de precisos, quando um método denominado N é invocado com uma lista de argumentos A em uma instância com um tipo de tempo de compilação C e um tipo de tempo de execução R (onde R seja C ou uma classe derivada de C), a invocação é processada da seguinte maneira:In precise terms, when a method named N is invoked with an argument list A on an instance with a compile-time type C and a run-time type R (where R is either C or a class derived from C), the invocation is processed as follows:

  • Em primeiro lugar, a resolução de sobrecarga é aplicada a C, N, e Apara selecionar um método específico M do conjunto de métodos declarados em e herdada por C.First, overload resolution is applied to C, N, and A, to select a specific method M from the set of methods declared in and inherited by C. Isso é descrito em invocações de método.This is described in Method invocations.
  • Então, se M é um método não virtual, M é invocado.Then, if M is a non-virtual method, M is invoked.
  • Caso contrário, M é um método virtual e a implementação mais derivada de M com relação ao R é invocado.Otherwise, M is a virtual method, and the most derived implementation of M with respect to R is invoked.

Para cada método virtual declarado em ou herdadas por uma classe, existe uma implementação derivada mais do método em relação a essa classe.For every virtual method declared in or inherited by a class, there exists a most derived implementation of the method with respect to that class. A implementação mais derivada de um método virtual M em relação a uma classe R é determinado da seguinte maneira:The most derived implementation of a virtual method M with respect to a class R is determined as follows:

  • Se R contém o apresentando virtual declaração de M, em seguida, essa é a implementação mais derivada de M.If R contains the introducing virtual declaration of M, then this is the most derived implementation of M.
  • Caso contrário, se R contém uma override dos M, em seguida, essa é a implementação mais derivada de M.Otherwise, if R contains an override of M, then this is the most derived implementation of M.
  • Caso contrário, a maioria implementação derivada da M em relação às R é o mesmo que a implementação mais derivada de M em relação a classe base direta de R.Otherwise, the most derived implementation of M with respect to R is the same as the most derived implementation of M with respect to the direct base class of R.

O exemplo a seguir ilustra as diferenças entre os métodos virtuais e não virtuais:The following example illustrates the differences between virtual and non-virtual methods:

using System;

class A
{
    public void F() { Console.WriteLine("A.F"); }

    public virtual void G() { Console.WriteLine("A.G"); }
}

class B: A
{
    new public void F() { Console.WriteLine("B.F"); }

    public override void G() { Console.WriteLine("B.G"); }
}

class Test
{
    static void Main() {
        B b = new B();
        A a = b;
        a.F();
        b.F();
        a.G();
        b.G();
    }
}

No exemplo, A apresenta um método não virtual F e um método virtual G.In the example, A introduces a non-virtual method F and a virtual method G. A classe B apresenta um novo método não virtual F, assim, ocultando a herdado Fe também substitui o método herdado G.The class B introduces a new non-virtual method F, thus hiding the inherited F, and also overrides the inherited method G. O exemplo produz a saída:The example produces the output:

A.F
B.F
B.G
B.G

Observe que a instrução a.G() invoca B.G, e não A.G.Notice that the statement a.G() invokes B.G, not A.G. Isso ocorre porque o tempo de execução de tipo da instância (que é B), não o tipo de tempo de compilação da instância (que é A), determina a implementação real do método para invocar.This is because the run-time type of the instance (which is B), not the compile-time type of the instance (which is A), determines the actual method implementation to invoke.

Porque os métodos podem ocultar métodos herdados, é possível que uma classe conter vários métodos virtuais com a mesma assinatura.Because methods are allowed to hide inherited methods, it is possible for a class to contain several virtual methods with the same signature. Isso não apresenta um problema de ambiguidade, desde que todos, exceto o método mais derivado estão ocultos.This does not present an ambiguity problem, since all but the most derived method are hidden. No exemploIn the example

using System;

class A
{
    public virtual void F() { Console.WriteLine("A.F"); }
}

class B: A
{
    public override void F() { Console.WriteLine("B.F"); }
}

class C: B
{
    new public virtual void F() { Console.WriteLine("C.F"); }
}

class D: C
{
    public override void F() { Console.WriteLine("D.F"); }
}

class Test
{
    static void Main() {
        D d = new D();
        A a = d;
        B b = d;
        C c = d;
        a.F();
        b.F();
        c.F();
        d.F();
    }
}

o C e D classes contêm dois métodos virtuais com a mesma assinatura: Aquele introduzido por A e um introduzido por C.the C and D classes contain two virtual methods with the same signature: The one introduced by A and the one introduced by C. O método introduzido por C oculta o método herdado de A.The method introduced by C hides the method inherited from A. Assim, a declaração de substituição em D substitui o método introduzido pela C, e não é possível D substituir o método introduzido por A.Thus, the override declaration in D overrides the method introduced by C, and it is not possible for D to override the method introduced by A. O exemplo produz a saída:The example produces the output:

B.F
B.F
D.F
D.F

Observe que é possível invocar o método virtual oculto acessando uma instância de D por meio de um menor derivado tipo no qual o método não está oculto.Note that it is possible to invoke the hidden virtual method by accessing an instance of D through a less derived type in which the method is not hidden.

Substituir métodosOverride methods

Quando uma declaração de método de instância inclui um override modificador, o método deve ser um substituir método.When an instance method declaration includes an override modifier, the method is said to be an override method. Um método de substituição substitui um método virtual herdado com a mesma assinatura.An override method overrides an inherited virtual method with the same signature. Enquanto uma declaração de método virtual apresenta um novo método, uma declaração de método de substituição restringe um método virtual herdado existente fornecendo uma nova implementação do método.Whereas a virtual method declaration introduces a new method, an override method declaration specializes an existing inherited virtual method by providing a new implementation of that method.

O método substituído por um override declaração é conhecida como o substituída do método base.The method overridden by an override declaration is known as the overridden base method. Para um método de substituição M declarado em uma classe C, o método base substituído é determinado examinando-se cada tipo de classe base de C, começando com o tipo de classe base direta de C e continuando com cada sucessivas tipo de classe base direta, até em um tipo de classe base pelo menos um método acessível é localizado que tem a mesma assinatura que M após a substituição de argumentos de tipo.For an override method M declared in a class C, the overridden base method is determined by examining each base class type of C, starting with the direct base class type of C and continuing with each successive direct base class type, until in a given base class type at least one accessible method is located which has the same signature as M after substitution of type arguments. Para fins de localizar o método base substituído, um método é considerado acessível se estiver public, se ele estiver protected, se ele for protected internal, ou se ele for internal e declarado no mesmo programa como C.For the purposes of locating the overridden base method, a method is considered accessible if it is public, if it is protected, if it is protected internal, or if it is internal and declared in the same program as C.

Um erro de tempo de compilação ocorre, a menos que todos os itens a seguir são verdadeiras para uma declaração de substituição:A compile-time error occurs unless all of the following are true for an override declaration:

  • Um método base substituído pode estar localizado, conforme descrito acima.An overridden base method can be located as described above.
  • Não há exatamente um tal método base substituído.There is exactly one such overridden base method. Essa restrição tem efeito somente se o tipo de classe base é um tipo construído em que a substituição de argumentos de tipo faz a assinatura dos dois métodos o mesmo.This restriction has effect only if the base class type is a constructed type where the substitution of type arguments makes the signature of two methods the same.
  • O método base substituído é um virtual, abstrato ou substituir o método.The overridden base method is a virtual, abstract, or override method. Em outras palavras, o método base substituído não pode ser estático ou não virtual.In other words, the overridden base method cannot be static or non-virtual.
  • O método base substituído não é um método lacrado.The overridden base method is not a sealed method.
  • O método de substituição e o método base substituído têm o mesmo tipo de retorno.The override method and the overridden base method have the same return type.
  • A declaração de substituição e o método base substituído têm a mesma acessibilidade declarada.The override declaration and the overridden base method have the same declared accessibility. Em outras palavras, uma declaração de substituição não é possível alterar a acessibilidade do método virtual.In other words, an override declaration cannot change the accessibility of the virtual method. No entanto, se o método base substituído é protegido interno e é declarada em um assembly diferente do que o assembly que contém o método de substituição e em seguida, o método de substituição declarado acessibilidade deve ser protegida.However, if the overridden base method is protected internal and it is declared in a different assembly than the assembly containing the override method then the override method's declared accessibility must be protected.
  • A declaração de substituição não especifica o tipo de parâmetro-restrições cláusulas.The override declaration does not specify type-parameter-constraints-clauses. Em vez disso, as restrições são herdadas do método base substituído.Instead the constraints are inherited from the overridden base method. Observe que as restrições que são parâmetros de tipo no método substituído podem ser substituídas por argumentos de tipo na restrição herdado.Note that constraints that are type parameters in the overridden method may be replaced by type arguments in the inherited constraint. Isso pode levar a restrições que não são válidas quando explicitamente especificado, como tipos de valor ou tipos lacrados.This can lead to constraints that are not legal when explicitly specified, such as value types or sealed types.

O exemplo a seguir demonstra como as regras de substituição funcionam para classes genéricas:The following example demonstrates how the overriding rules work for generic classes:

abstract class C<T>
{
    public virtual T F() {...}
    public virtual C<T> G() {...}
    public virtual void H(C<T> x) {...}
}

class D: C<string>
{
    public override string F() {...}            // Ok
    public override C<string> G() {...}         // Ok
    public override void H(C<T> x) {...}        // Error, should be C<string>
}

class E<T,U>: C<U>
{
    public override U F() {...}                 // Ok
    public override C<U> G() {...}              // Ok
    public override void H(C<T> x) {...}        // Error, should be C<U>
}

Uma declaração de substituição pode acessar o método base substituído usando um base_access (acesso de Base).An override declaration can access the overridden base method using a base_access (Base access). No exemploIn the example

class A
{
    int x;

    public virtual void PrintFields() {
        Console.WriteLine("x = {0}", x);
    }
}

class B: A
{
    int y;

    public override void PrintFields() {
        base.PrintFields();
        Console.WriteLine("y = {0}", y);
    }
}

o base.PrintFields() invocação B invoca o PrintFields método declarado em A.the base.PrintFields() invocation in B invokes the PrintFields method declared in A. Um base_access desabilita o mecanismo de invocação virtual e simplesmente trata o método base como um método não virtual.A base_access disables the virtual invocation mechanism and simply treats the base method as a non-virtual method. Teve a invocação no B foi gravado ((A)this).PrintFields(), seria recursivamente invocar o PrintFields método declarado em B, não aquela declarada no A, desde que PrintFields é virtual e o tipo de tempo de execução do ((A)this) é B.Had the invocation in B been written ((A)this).PrintFields(), it would recursively invoke the PrintFields method declared in B, not the one declared in A, since PrintFields is virtual and the run-time type of ((A)this) is B.

Apenas, incluindo um override can modificador um método substituem outro método.Only by including an override modifier can a method override another method. Em todos os outros casos, um método com a mesma assinatura que um método herdado simplesmente oculta o método herdado.In all other cases, a method with the same signature as an inherited method simply hides the inherited method. No exemploIn the example

class A
{
    public virtual void F() {}
}

class B: A
{
    public virtual void F() {}        // Warning, hiding inherited F()
}

o F método no B não inclui um override modificador e, portanto, não substitui o F método na A.the F method in B does not include an override modifier and therefore does not override the F method in A. Em vez disso, o F método no B oculta o método na A, e um aviso é relatado como a declaração não inclui um new modificador.Rather, the F method in B hides the method in A, and a warning is reported because the declaration does not include a new modifier.

No exemploIn the example

class A
{
    public virtual void F() {}
}

class B: A
{
    new private void F() {}        // Hides A.F within body of B
}

class C: B
{
    public override void F() {}    // Ok, overrides A.F
}

o F método no B oculta virtual F método herdado do A.the F method in B hides the virtual F method inherited from A. Desde o novo F na B tem acesso privado, seu escopo inclui apenas o corpo da classe B e não se estende para C.Since the new F in B has private access, its scope only includes the class body of B and does not extend to C. Portanto, a declaração de F na C tem permissão para substituir o F herdado de A.Therefore, the declaration of F in C is permitted to override the F inherited from A.

Métodos lacradosSealed methods

Quando uma declaração de método de instância inclui um sealed modificador, que o método deve ser um lacrados método.When an instance method declaration includes a sealed modifier, that method is said to be a sealed method. Se uma declaração de método de instância inclui o sealed modificador, ele também deve incluir o override modificador.If an instance method declaration includes the sealed modifier, it must also include the override modifier. Usar o sealed modificador impede que uma classe derivada ainda mais, substituindo o método.Use of the sealed modifier prevents a derived class from further overriding the method.

No exemploIn the example

using System;

class A
{
    public virtual void F() {
        Console.WriteLine("A.F");
    }

    public virtual void G() {
        Console.WriteLine("A.G");
    }
}

class B: A
{
    sealed override public void F() {
        Console.WriteLine("B.F");
    } 

    override public void G() {
        Console.WriteLine("B.G");
    } 
}

class C: B
{
    override public void G() {
        Console.WriteLine("C.G");
    } 
}

a classe B fornece dois métodos de substituição: uma F método que tem o sealed modificador e um G método que não tem.the class B provides two override methods: an F method that has the sealed modifier and a G method that does not. Buso do lacrado modifier impede C substituam ainda mais F.B's use of the sealed modifier prevents C from further overriding F.

Métodos abstratosAbstract methods

Quando uma declaração de método de instância inclui um abstract modificador, que o método deve ser um método abstrato.When an instance method declaration includes an abstract modifier, that method is said to be an abstract method. Embora um método abstrato também é implicitamente um método virtual, ele não pode ter o modificador virtual.Although an abstract method is implicitly also a virtual method, it cannot have the modifier virtual.

Uma declaração de método abstrato apresenta um novo método virtual, mas não fornece uma implementação desse método.An abstract method declaration introduces a new virtual method but does not provide an implementation of that method. Em vez disso, as classes derivadas não abstratas devem fornecer sua própria implementação, substituindo esse método.Instead, non-abstract derived classes are required to provide their own implementation by overriding that method. Como um método abstrato não fornece nenhuma implementação real, o method_body de um método abstrato consiste apenas em um ponto e vírgula.Because an abstract method provides no actual implementation, the method_body of an abstract method simply consists of a semicolon.

Declarações de método abstrato são permitidas apenas em classes abstratas (classes abstratas).Abstract method declarations are only permitted in abstract classes (Abstract classes).

No exemploIn the example

public abstract class Shape
{
    public abstract void Paint(Graphics g, Rectangle r);
}

public class Ellipse: Shape
{
    public override void Paint(Graphics g, Rectangle r) {
        g.DrawEllipse(r);
    }
}

public class Box: Shape
{
    public override void Paint(Graphics g, Rectangle r) {
        g.DrawRect(r);
    }
}

o Shape classe define o conceito abstrato de um objeto de forma geométrica que pode pintar em si.the Shape class defines the abstract notion of a geometrical shape object that can paint itself. O Paint método é abstrato porque não há nenhuma implementação padrão significativos.The Paint method is abstract because there is no meaningful default implementation. O Ellipse e Box classes são concretas Shape implementações.The Ellipse and Box classes are concrete Shape implementations. Como essas classes são não-abstrata, eles são necessários para substituir o Paint método e fornecer uma implementação real.Because these classes are non-abstract, they are required to override the Paint method and provide an actual implementation.

É um erro de tempo de compilação para um base_access (acesso de Base) para fazer referência a um método abstrato.It is a compile-time error for a base_access (Base access) to reference an abstract method. No exemploIn the example

abstract class A
{
    public abstract void F();
}

class B: A
{
    public override void F() {
        base.F();                        // Error, base.F is abstract
    }
}

um erro de tempo de compilação é relatado para o base.F() invocação porque faz referência a um método abstrato.a compile-time error is reported for the base.F() invocation because it references an abstract method.

Uma declaração de método abstrato tem permissão para substituir um método virtual.An abstract method declaration is permitted to override a virtual method. Isso permite que uma classe abstrata forçar a nova implementação do método em classes derivadas e torna a implementação original do método não está disponível.This allows an abstract class to force re-implementation of the method in derived classes, and makes the original implementation of the method unavailable. No exemploIn the example

using System;

class A
{
    public virtual void F() {
        Console.WriteLine("A.F");
    }
}

abstract class B: A
{
    public abstract override void F();
}

class C: B
{
    public override void F() {
        Console.WriteLine("C.F");
    }
}

classe A declara um método virtual, a classe B substitui esse método com um método abstrato e classe C substitui o método abstrato para fornecer sua própria implementação.class A declares a virtual method, class B overrides this method with an abstract method, and class C overrides the abstract method to provide its own implementation.

Métodos externosExternal methods

Quando uma declaração de método inclui um extern modificador, que o método deve ser um método externo.When a method declaration includes an extern modifier, that method is said to be an external method. Métodos externos são implementados externamente, normalmente usando um idioma diferente do c#.External methods are implemented externally, typically using a language other than C#. Como uma declaração de método externo não fornece nenhuma implementação real, o method_body de um método externo consiste apenas em um ponto e vírgula.Because an external method declaration provides no actual implementation, the method_body of an external method simply consists of a semicolon. Um método externo não pode ser genérico.An external method may not be generic.

O extern modificador é normalmente usado em conjunto com um DllImport atributo (interoperação com componentes COM e Win32), permitindo que os métodos externos a ser implementada por DLLs (bibliotecas de vínculo dinâmico).The extern modifier is typically used in conjunction with a DllImport attribute (Interoperation with COM and Win32 components), allowing external methods to be implemented by DLLs (Dynamic Link Libraries). O ambiente de execução pode dar suporte a outros mecanismos, no qual as implementações de métodos externos podem ser fornecidas.The execution environment may support other mechanisms whereby implementations of external methods can be provided.

Quando um método externo inclui um DllImport atributo, a declaração do método também deve incluir um static modificador.When an external method includes a DllImport attribute, the method declaration must also include a static modifier. Este exemplo demonstra o uso do extern modificador e o DllImport atributo:This example demonstrates the use of the extern modifier and the DllImport attribute:

using System.Text;
using System.Security.Permissions;
using System.Runtime.InteropServices;

class Path
{
    [DllImport("kernel32", SetLastError=true)]
    static extern bool CreateDirectory(string name, SecurityAttribute sa);

    [DllImport("kernel32", SetLastError=true)]
    static extern bool RemoveDirectory(string name);

    [DllImport("kernel32", SetLastError=true)]
    static extern int GetCurrentDirectory(int bufSize, StringBuilder buf);

    [DllImport("kernel32", SetLastError=true)]
    static extern bool SetCurrentDirectory(string name);
}

Métodos parciais (recapitulação)Partial methods (recap)

Quando uma declaração de método inclui um partial modificador, que o método deve ser um método parcial.When a method declaration includes a partial modifier, that method is said to be a partial method. Métodos parciais só podem ser declarados como membros de tipos parciais (tipos parciais) e estão sujeitos a várias restrições.Partial methods can only be declared as members of partial types (Partial types), and are subject to a number of restrictions. Métodos parciais são descritos na métodos parciais.Partial methods are further described in Partial methods.

Métodos de extensãoExtension methods

Quando o primeiro parâmetro de um método inclui o this modificador, que o método deve ser um método de extensão.When the first parameter of a method includes the this modifier, that method is said to be an extension method. Métodos de extensão só podem ser declarados em classes estáticas não genérico, não aninhadas.Extension methods can only be declared in non-generic, non-nested static classes. O primeiro parâmetro de um método de extensão não pode ter nenhum modificador diferente de this, e o tipo de parâmetro não pode ser um tipo de ponteiro.The first parameter of an extension method can have no modifiers other than this, and the parameter type cannot be a pointer type.

Este é um exemplo de uma classe estática que declara dois métodos de extensão:The following is an example of a static class that declares two extension methods:

public static class Extensions
{
    public static int ToInt32(this string s) {
        return Int32.Parse(s);
    }

    public static T[] Slice<T>(this T[] source, int index, int count) {
        if (index < 0 || count < 0 || source.Length - index < count)
            throw new ArgumentException();
        T[] result = new T[count];
        Array.Copy(source, index, result, 0, count);
        return result;
    }
}

Um método de extensão é um método estático normal.An extension method is a regular static method. Além disso, em que sua classe estática delimitador no escopo, um método de extensão pode ser invocado usando sintaxe de invocação de método de instância (invocações de método de extensão), usando a expressão de receptor como o primeiro argumento.In addition, where its enclosing static class is in scope, an extension method can be invoked using instance method invocation syntax (Extension method invocations), using the receiver expression as the first argument.

O programa a seguir usa os métodos de extensão declarados acima:The following program uses the extension methods declared above:

static class Program
{
    static void Main() {
        string[] strings = { "1", "22", "333", "4444" };
        foreach (string s in strings.Slice(1, 2)) {
            Console.WriteLine(s.ToInt32());
        }
    }
}

O Slice método está disponível na string[]e o ToInt32 método está disponível no string, porque eles foram declarados como métodos de extensão.The Slice method is available on the string[], and the ToInt32 method is available on string, because they have been declared as extension methods. O significado do programa é o mesmo que as chamadas de método estático normal seguinte, usando:The meaning of the program is the same as the following, using ordinary static method calls:

static class Program
{
    static void Main() {
        string[] strings = { "1", "22", "333", "4444" };
        foreach (string s in Extensions.Slice(strings, 1, 2)) {
            Console.WriteLine(Extensions.ToInt32(s));
        }
    }
}

Corpo do métodoMethod body

O method_body de um método de declaração consiste em um corpo do bloco, um corpo de expressão ou um ponto e vírgula.The method_body of a method declaration consists of either a block body, an expression body or a semicolon.

O tipo de resultado de um método é void se for o tipo de retorno void, ou se o método é assíncrono e o tipo de retorno é System.Threading.Tasks.Task.The result type of a method is void if the return type is void, or if the method is async and the return type is System.Threading.Tasks.Task. Caso contrário, o tipo de resultado de um método não assíncrono é seu tipo de retorno e o tipo de resultado de um método assíncrono com o tipo de retorno System.Threading.Tasks.Task<T> é T.Otherwise, the result type of a non-async method is its return type, and the result type of an async method with return type System.Threading.Tasks.Task<T> is T.

Quando um método tem um void resultar de tipo e um corpo do bloco return instruções (a instrução return) no bloco não são permitidos para especificar uma expressão.When a method has a void result type and a block body, return statements (The return statement) in the block are not permitted to specify an expression. Se a execução do bloco de um método void é concluída normalmente (ou seja, controlam fluxos de fora do corpo do método), que o método simplesmente retorna para seu chamador atual.If execution of the block of a void method completes normally (that is, control flows off the end of the method body), that method simply returns to its current caller.

Quando um método tem um void resultado e um corpo de expressão, a expressão E deve ser um statement_expression, e o corpo é exatamente equivalente a um corpo do bloco do formulário { E; }.When a method has a void result and an expression body, the expression E must be a statement_expression, and the body is exactly equivalent to a block body of the form { E; }.

Quando um método tem um tipo de resultado não nulo e um bloco de corpo, cada return instrução do bloco deve especificar uma expressão que é implicitamente conversível para o tipo de resultado.When a method has a non-void result type and a block body, each return statement in the block must specify an expression that is implicitly convertible to the result type. O ponto de extremidade de um corpo do bloco de um método que retorna o valor não deve ser acessível.The endpoint of a block body of a value-returning method must not be reachable. Em outras palavras, em um método de retorno de valor com um corpo do bloco, o controle não tem permissão para fluir para fora o final do corpo do método.In other words, in a value-returning method with a block body, control is not permitted to flow off the end of the method body.

Quando um método tem um tipo de resultado não nulo e um corpo de expressão, a expressão deve ser implicitamente conversível para o tipo de resultado e o corpo é exatamente equivalente a um corpo do bloco do formulário { return E; }.When a method has a non-void result type and an expression body, the expression must be implicitly convertible to the result type, and the body is exactly equivalent to a block body of the form { return E; }.

No exemploIn the example

class A
{
    public int F() {}            // Error, return value required

    public int G() {
        return 1;
    }

    public int H(bool b) {
        if (b) {
            return 1;
        }
        else {
            return 0;
        }
    }

    public int I(bool b) => b ? 1 : 0;
}

o valor de retorno F método resulta em um erro de tempo de compilação porque o controle pode fluir para fora o final do corpo do método.the value-returning F method results in a compile-time error because control can flow off the end of the method body. O G e H métodos estão corretos, porque todos os possíveis caminhos de execução terminam com uma instrução return que especifica um valor de retorno.The G and H methods are correct because all possible execution paths end in a return statement that specifies a return value. O I método está correto, pois seu corpo é equivalente a um bloco de instrução com apenas uma única instrução return nele.The I method is correct, because its body is equivalent to a statement block with just a single return statement in it.

Sobrecarga de métodoMethod overloading

As regras de resolução de sobrecarga de método são descritas em inferência de tipo.The method overload resolution rules are described in Type inference.

PropriedadesProperties

Um propriedade é um membro que fornece acesso a uma característica de um objeto ou uma classe.A property is a member that provides access to a characteristic of an object or a class. Exemplos de propriedades incluem o comprimento de uma cadeia de caracteres, o tamanho de uma fonte, a legenda de uma janela, o nome de um cliente e assim por diante.Examples of properties include the length of a string, the size of a font, the caption of a window, the name of a customer, and so on. As propriedades são uma extensão natural dos campos — elas são denominadas membros com tipos associados e a sintaxe para acessar os campos e propriedades é o mesmo.Properties are a natural extension of fields—both are named members with associated types, and the syntax for accessing fields and properties is the same. No entanto, diferentemente dos campos, as propriedades não denotam locais de armazenamento.However, unlike fields, properties do not denote storage locations. Em vez disso, as propriedades têm acessadores que especificam as instruções a serem executadas quando os valores forem lidos ou gravados.Instead, properties have accessors that specify the statements to be executed when their values are read or written. Propriedades, portanto, fornecem um mecanismo para associar as ações com a leitura e gravação de atributos de um objeto; Além disso, eles permitem que esses atributos a ser computado.Properties thus provide a mechanism for associating actions with the reading and writing of an object's attributes; furthermore, they permit such attributes to be computed.

As propriedades são declaradas usando property_declarations:Properties are declared using property_declarations:

property_declaration
    : attributes? property_modifier* type member_name property_body
    ;

property_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | property_modifier_unsafe
    ;

property_body
    : '{' accessor_declarations '}' property_initializer?
    | '=>' expression ';'
    ;

property_initializer
    : '=' variable_initializer ';'
    ;

Um property_declaration pode incluir um conjunto de atributos (atributos) e uma combinação válida de as quatro modificadores de acesso (modificadores de acesso ), o new (o novo modificador), static (métodos estáticos e de instância), virtual (métodos virtuais), override (Substituir métodos), sealed (lacrados métodos), abstract (métodos abstratos), e extern (Métodos externos) modificadores.A property_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), static (Static and instance methods), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

Declarações de propriedade estão sujeitos às mesmas regras de declarações de método (métodos) em relação a combinações válidas de modificadores.Property declarations are subject to the same rules as method declarations (Methods) with regard to valid combinations of modifiers.

O tipo de uma propriedade de declaração especifica o tipo da propriedade introduzida pela declaração e o member_name Especifica o nome da propriedade.The type of a property declaration specifies the type of the property introduced by the declaration, and the member_name specifies the name of the property. A menos que a propriedade é uma implementação de membro de interface explícita, o member_name é simplesmente uma identificador.Unless the property is an explicit interface member implementation, the member_name is simply an identifier. Para uma implementação de membro de interface explícita (implementações de membros de interface explícita), o member_name consiste em um interface_type seguido por um " ."e uma identificador.For an explicit interface member implementation (Explicit interface member implementations), the member_name consists of an interface_type followed by a "." and an identifier.

O tipo de uma propriedade deve ser pelo menos tão acessível quanto a própria propriedade (restrições de acessibilidade).The type of a property must be at least as accessible as the property itself (Accessibility constraints).

Um property_body qualquer um pode consistir de uma corpo do acessador ou uma corpo da expressão.A property_body may either consist of an accessor body or an expression body. Em um corpo de acessador accessor_declarations, que deve ser colocada em "{"e"}" tokens, declare acessadores (acessadores) da propriedade.In an accessor body, accessor_declarations, which must be enclosed in "{" and "}" tokens, declare the accessors (Accessors) of the property. Os acessadores de especificam as instruções executáveis associadas com a leitura e gravação de propriedade.The accessors specify the executable statements associated with reading and writing the property.

Um corpo de expressão consiste => seguido por um expressão E e um ponto e vírgula é exatamente equivalente para o corpo da instrução { get { return E; } }e apenas, portanto, pode ser usado para especificar apenas de getter propriedades em que o resultado do getter é determinado por uma única expressão.An expression body consisting of => followed by an expression E and a semicolon is exactly equivalent to the statement body { get { return E; } }, and can therefore only be used to specify getter-only properties where the result of the getter is given by a single expression.

Um property_initializer só podem ser designados para uma propriedade implementada automaticamente (implementadas automaticamente propriedades) e faz com que a inicialização do campo subjacente de tais as propriedades com o valor fornecido pelo expressão.A property_initializer may only be given for an automatically implemented property (Automatically implemented properties), and causes the initialization of the underlying field of such properties with the value given by the expression.

Embora a sintaxe para acessar uma propriedade é o mesmo que para um campo, uma propriedade não é classificada como uma variável.Even though the syntax for accessing a property is the same as that for a field, a property is not classified as a variable. Portanto, não é possível passar uma propriedade como uma ref ou out argumento.Thus, it is not possible to pass a property as a ref or out argument.

Quando uma declaração de propriedade inclui um extern modificador, a propriedade deve ser um propriedade externa.When a property declaration includes an extern modifier, the property is said to be an external property. Como uma declaração de propriedade externa não fornece nenhuma implementação real, cada um dos seus accessor_declarations consiste em um ponto e vírgula.Because an external property declaration provides no actual implementation, each of its accessor_declarations consists of a semicolon.

Propriedades estáticos e de instânciaStatic and instance properties

Quando uma declaração de propriedade inclui um static modificador, a propriedade deve ser um propriedade estática.When a property declaration includes a static modifier, the property is said to be a static property. Quando nenhum static modificador estiver presente, a propriedade deve ser um propriedade da instância.When no static modifier is present, the property is said to be an instance property.

Uma propriedade estática não está associada uma instância específica e é um erro de tempo de compilação para se referir a this nos acessadores de uma propriedade estática.A static property is not associated with a specific instance, and it is a compile-time error to refer to this in the accessors of a static property.

Uma propriedade de instância está associada uma determinada instância de uma classe, e essa instância pode ser acessada como this (esse acesso) nos acessadores da propriedade.An instance property is associated with a given instance of a class, and that instance can be accessed as this (This access) in the accessors of that property.

Quando uma propriedade é referenciada em uma member_access (acesso de membro) do formulário E.M, se M é uma propriedade estática, E deve indicar um tipo que contém Me se M é uma propriedade de instância, E preciso marcar uma instância de um tipo que contém M.When a property is referenced in a member_access (Member access) of the form E.M, if M is a static property, E must denote a type containing M, and if M is an instance property, E must denote an instance of a type containing M.

As diferenças entre static e membros de instância são discutidos mais detalhadamente em membros estáticos e de instância.The differences between static and instance members are discussed further in Static and instance members.

AcessadoresAccessors

O accessor_declarations de uma propriedade, especifique as instruções executáveis associadas com a leitura e gravação a essa propriedade.The accessor_declarations of a property specify the executable statements associated with reading and writing that property.

accessor_declarations
    : get_accessor_declaration set_accessor_declaration?
    | set_accessor_declaration get_accessor_declaration?
    ;

get_accessor_declaration
    : attributes? accessor_modifier? 'get' accessor_body
    ;

set_accessor_declaration
    : attributes? accessor_modifier? 'set' accessor_body
    ;

accessor_modifier
    : 'protected'
    | 'internal'
    | 'private'
    | 'protected' 'internal'
    | 'internal' 'protected'
    ;

accessor_body
    : block
    | ';'
    ;

As declarações de acessador consistem em uma get_accessor_declaration, um set_accessor_declaration, ou ambos.The accessor declarations consist of a get_accessor_declaration, a set_accessor_declaration, or both. Cada declaração de acessador consiste o token get ou set seguido de um recurso opcional accessor_modifier e um accessor_body.Each accessor declaration consists of the token get or set followed by an optional accessor_modifier and an accessor_body.

O uso de accessor_modifiers é regido pelos seguintes restrições:The use of accessor_modifiers is governed by the following restrictions:

  • Uma accessor_modifier não pode ser usado em uma interface ou em uma implementação de membro de interface explícita.An accessor_modifier may not be used in an interface or in an explicit interface member implementation.
  • Para uma propriedade ou indexador que não tem nenhum override modificador, uma accessor_modifier é permitido somente se a propriedade ou o indexador tiver tanto um get e set acessador e, em seguida, é permitida apenas em um desses acessadores.For a property or indexer that has no override modifier, an accessor_modifier is permitted only if the property or indexer has both a get and set accessor, and then is permitted only on one of those accessors.
  • Para uma propriedade ou indexador que inclui um override modificador, um acessador deve corresponder a accessor_modifier, se houver, do acessador que está sendo substituído.For a property or indexer that includes an override modifier, an accessor must match the accessor_modifier, if any, of the accessor being overridden.
  • O accessor_modifier deve declarar a acessibilidade é estritamente mais restritiva que a acessibilidade declarada de propriedade ou indexador em si.The accessor_modifier must declare an accessibility that is strictly more restrictive than the declared accessibility of the property or indexer itself. Para ser preciso:To be precise:
    • Se a propriedade ou indexador tem uma acessibilidade declarada de public, o accessor_modifier pode ser protected internal, internal, protected, ou private.If the property or indexer has a declared accessibility of public, the accessor_modifier may be either protected internal, internal, protected, or private.
    • Se a propriedade ou indexador tem uma acessibilidade declarada de protected internal, o accessor_modifier pode ser internal, protected, ou private.If the property or indexer has a declared accessibility of protected internal, the accessor_modifier may be either internal, protected, or private.
    • Se a propriedade ou indexador tem uma acessibilidade declarada de internal ou protected, o accessor_modifier deve ser private.If the property or indexer has a declared accessibility of internal or protected, the accessor_modifier must be private.
    • Se a propriedade ou indexador tem uma acessibilidade declarada de private, nenhum accessor_modifier pode ser usado.If the property or indexer has a declared accessibility of private, no accessor_modifier may be used.

Para abstract e extern propriedades, o accessor_body para cada acessador especificado é simplesmente um ponto e vírgula.For abstract and extern properties, the accessor_body for each accessor specified is simply a semicolon. Uma propriedade não-abstrata, não-externo pode ter cada accessor_body ser um ponto e vírgula, caso em que ele é um propriedade implementada automaticamente (implementada automaticamente propriedades ).A non-abstract, non-extern property may have each accessor_body be a semicolon, in which case it is an automatically implemented property (Automatically implemented properties). Uma propriedade implementada automaticamente deve ter pelo menos um acessador get.An automatically implemented property must have at least a get accessor. Para os acessadores de qualquer outra não-abstrata, não extern propriedade, o accessor_body é um bloco que especifica as instruções a serem executadas quando o acessador correspondente é invocado.For the accessors of any other non-abstract, non-extern property, the accessor_body is a block which specifies the statements to be executed when the corresponding accessor is invoked.

Um get acessador corresponde a um método sem parâmetros com um valor de retorno do tipo de propriedade.A get accessor corresponds to a parameterless method with a return value of the property type. Exceto como o destino de uma atribuição, quando uma propriedade é referenciada em uma expressão, o get acessador da propriedade é invocado para calcular o valor da propriedade (valores das expressões).Except as the target of an assignment, when a property is referenced in an expression, the get accessor of the property is invoked to compute the value of the property (Values of expressions). O corpo de uma get acessador deve obedecer às regras para retornar o valor métodos descritos corpo do método.The body of a get accessor must conform to the rules for value-returning methods described in Method body. Em particular, todos os return instruções no corpo de um get acessador deve especificar uma expressão que é implicitamente conversível para o tipo de propriedade.In particular, all return statements in the body of a get accessor must specify an expression that is implicitly convertible to the property type. Além disso, o ponto de extremidade de um get acessador não pode estar acessível.Furthermore, the endpoint of a get accessor must not be reachable.

Um set acessador corresponde a um método com um parâmetro de valor único do tipo de propriedade e um void tipo de retorno.A set accessor corresponds to a method with a single value parameter of the property type and a void return type. O parâmetro implícito de um set acessador é sempre denominado value.The implicit parameter of a set accessor is always named value. Quando uma propriedade é referenciada como o destino de uma atribuição (operadores de atribuição), ou como o operando da ++ ou -- (incremento de sufixo e operadores de decremento, Incremento de prefixo e operadores de decremento), o set acessador é invocado com um argumento (cujo valor é o do lado direito da atribuição ou o operando das ++ ou -- operador) que fornece o novo valor (atribuição simples).When a property is referenced as the target of an assignment (Assignment operators), or as the operand of ++ or -- (Postfix increment and decrement operators, Prefix increment and decrement operators), the set accessor is invoked with an argument (whose value is that of the right-hand side of the assignment or the operand of the ++ or -- operator) that provides the new value (Simple assignment). O corpo de uma set acessador deve estar de acordo com as regras para void métodos descritos corpo do método.The body of a set accessor must conform to the rules for void methods described in Method body. Em particular, return instruções de set corpo do acessador não são permitidos para especificar uma expressão.In particular, return statements in the set accessor body are not permitted to specify an expression. Uma vez que um set acessador implicitamente tem um parâmetro chamado value, é um erro de tempo de compilação para uma declaração de constante ou variável local em um set acessador esse nome.Since a set accessor implicitly has a parameter named value, it is a compile-time error for a local variable or constant declaration in a set accessor to have that name.

Com base na presença ou ausência do get e set acessadores, uma propriedade é classificado da seguinte maneira:Based on the presence or absence of the get and set accessors, a property is classified as follows:

  • Uma propriedade que inclui tanto uma get acessador e um set acessador deve ser um leitura-gravação propriedade.A property that includes both a get accessor and a set accessor is said to be a read-write property.
  • Uma propriedade que tem apenas um get acessador deve ser um somente leitura propriedade.A property that has only a get accessor is said to be a read-only property. Ele é um erro de tempo de compilação para uma propriedade somente leitura ser o destino de uma atribuição.It is a compile-time error for a read-only property to be the target of an assignment.
  • Uma propriedade que tem apenas um set acessador deve ser um somente gravação propriedade.A property that has only a set accessor is said to be a write-only property. Exceto como o destino de uma atribuição, ele é um erro de tempo de compilação para fazer referência a uma propriedade somente gravação em uma expressão.Except as the target of an assignment, it is a compile-time error to reference a write-only property in an expression.

No exemploIn the example

public class Button: Control
{
    private string caption;

    public string Caption {
        get {
            return caption;
        }
        set {
            if (caption != value) {
                caption = value;
                Repaint();
            }
        }
    }

    public override void Paint(Graphics g, Rectangle r) {
        // Painting code goes here
    }
}

o Button controle declara um público Caption propriedade.the Button control declares a public Caption property. O get acessador do Caption propriedade retorna a cadeia de caracteres armazenada em particular caption campo.The get accessor of the Caption property returns the string stored in the private caption field. O set acessador verifica se o novo valor é diferente do valor atual e, nesse caso, ele armazena o novo valor e redesenha o controle.The set accessor checks if the new value is different from the current value, and if so, it stores the new value and repaints the control. Propriedades geralmente seguem o padrão mostrado acima: O get acessador simplesmente retorna um valor armazenado em um campo privado e o set acessador modifica esse campo particular e, em seguida, executa ações adicionais necessárias para atualizar totalmente o estado do objeto.Properties often follow the pattern shown above: The get accessor simply returns a value stored in a private field, and the set accessor modifies that private field and then performs any additional actions required to fully update the state of the object.

Dada a Button classe acima, o seguinte é um exemplo de uso do Caption propriedade:Given the Button class above, the following is an example of use of the Caption property:

Button okButton = new Button();
okButton.Caption = "OK";            // Invokes set accessor
string s = okButton.Caption;        // Invokes get accessor

Aqui, o set acessador é invocado, atribuindo um valor para a propriedade e o get acessador é invocado por fazer referência à propriedade em uma expressão.Here, the set accessor is invoked by assigning a value to the property, and the get accessor is invoked by referencing the property in an expression.

O get e set acessadores de uma propriedade não são membros diferentes e não é possível declarar os acessadores de uma propriedade separadamente.The get and set accessors of a property are not distinct members, and it is not possible to declare the accessors of a property separately. Como tal, não é possível que os dois acessadores de uma propriedade de leitura / gravação ter acessibilidade diferente.As such, it is not possible for the two accessors of a read-write property to have different accessibility. O exemploThe example

class A
{
    private string name;

    public string Name {                // Error, duplicate member name
        get { return name; }
    }

    public string Name {                // Error, duplicate member name
        set { name = value; }
    }
}

não declara uma única propriedade de leitura / gravação.does not declare a single read-write property. Em vez disso, ele declara duas propriedades com o mesmo nome, um somente leitura e somente gravação.Rather, it declares two properties with the same name, one read-only and one write-only. Como dois membros declarados na mesma classe não podem ter o mesmo nome, o exemplo faz com que ocorra um erro de tempo de compilação.Since two members declared in the same class cannot have the same name, the example causes a compile-time error to occur.

Quando uma classe derivada não declara uma propriedade com o mesmo nome como uma propriedade herdada, a propriedade derivada oculta a propriedade herdada com relação à leitura e gravação.When a derived class declares a property by the same name as an inherited property, the derived property hides the inherited property with respect to both reading and writing. No exemploIn the example

class A
{
    public int P {
        set {...}
    }
}

class B: A
{
    new public int P {
        get {...}
    }
}

o P propriedade na B oculta a P propriedade no A em relação à leitura e gravação.the P property in B hides the P property in A with respect to both reading and writing. Dessa forma, nas instruçõesThus, in the statements

B b = new B();
b.P = 1;          // Error, B.P is read-only
((A)b).P = 1;     // Ok, reference to A.P

a atribuição ao b.P causa um erro de tempo de compilação a ser relatado, desde o somente leitura P propriedade na B oculta a somente gravação P propriedade no A.the assignment to b.P causes a compile-time error to be reported, since the read-only P property in B hides the write-only P property in A. No entanto, observe que uma conversão pode ser usada para acessar o oculto P propriedade.Note, however, that a cast can be used to access the hidden P property.

Diferentemente dos campos públicos, propriedades fornecem uma separação entre o estado interno de um objeto e sua interface pública.Unlike public fields, properties provide a separation between an object's internal state and its public interface. Considere o exemplo:Consider the example:

class Label
{
    private int x, y;
    private string caption;

    public Label(int x, int y, string caption) {
        this.x = x;
        this.y = y;
        this.caption = caption;
    }

    public int X {
        get { return x; }
    }

    public int Y {
        get { return y; }
    }

    public Point Location {
        get { return new Point(x, y); }
    }

    public string Caption {
        get { return caption; }
    }
}

Aqui, o Label classe usa dois int campos, x e y, para armazenar seu local.Here, the Label class uses two int fields, x and y, to store its location. O local é publicamente exposta como uma X e uma Y propriedade e como um Location propriedade do tipo Point.The location is publicly exposed both as an X and a Y property and as a Location property of type Point. Se, em uma versão futura do Label, ele se torna mais conveniente armazenar o local como um Point internamente, a alteração pode ser feita sem afetar a interface pública da classe:If, in a future version of Label, it becomes more convenient to store the location as a Point internally, the change can be made without affecting the public interface of the class:

class Label
{
    private Point location;
    private string caption;

    public Label(int x, int y, string caption) {
        this.location = new Point(x, y);
        this.caption = caption;
    }

    public int X {
        get { return location.x; }
    }

    public int Y {
        get { return location.y; }
    }

    public Point Location {
        get { return location; }
    }

    public string Caption {
        get { return caption; }
    }
}

Tinha x e y em vez disso, foram public readonly campos, teria sido impossível fazer uma alteração para o Label classe.Had x and y instead been public readonly fields, it would have been impossible to make such a change to the Label class.

Expõe estado por meio das propriedades não é necessariamente menos eficiente do que expor campos diretamente.Exposing state through properties is not necessarily any less efficient than exposing fields directly. Em particular, quando uma propriedade é não virtual e contém apenas uma pequena quantidade de código, o ambiente de execução pode substituir chamadas para acessadores com o código real de acessadores.In particular, when a property is non-virtual and contains only a small amount of code, the execution environment may replace calls to accessors with the actual code of the accessors. Esse processo é conhecido como inlining, e torna o acesso de propriedade tão eficiente quanto o acesso de campo, mas preserva a maior flexibilidade de propriedades.This process is known as inlining, and it makes property access as efficient as field access, yet preserves the increased flexibility of properties.

Desde a invocação de um get acessador é conceitualmente equivalente ao ler o valor de um campo, ele é considerado um estilo ruim de programação para get acessadores ter efeitos colaterais observáveis.Since invoking a get accessor is conceptually equivalent to reading the value of a field, it is considered bad programming style for get accessors to have observable side-effects. No exemploIn the example

class Counter
{
    private int next;

    public int Next {
        get { return next++; }
    }
}

O valor da Next propriedade depende do número de vezes que a propriedade foi acessada anteriormente.the value of the Next property depends on the number of times the property has previously been accessed. Assim, acessar a propriedade produz um efeito colateral observável, e a propriedade deve ser implementada como um método em vez disso.Thus, accessing the property produces an observable side-effect, and the property should be implemented as a method instead.

A convenção de "sem efeitos colaterais" para get acessadores não significa que get acessadores sempre devem ser escritos para simplesmente retornar valores armazenados nos campos.The "no side-effects" convention for get accessors doesn't mean that get accessors should always be written to simply return values stored in fields. Na verdade, get acessadores geralmente calcular o valor de uma propriedade ao acessar vários campos ou invocar métodos.Indeed, get accessors often compute the value of a property by accessing multiple fields or invoking methods. No entanto, projetado corretamente get acessador não executará nenhuma ação que causam alterações observáveis no estado do objeto.However, a properly designed get accessor performs no actions that cause observable changes in the state of the object.

Propriedades podem ser usadas para atrasar a inicialização de um recurso até o momento em que ele é referenciado pela primeira vez.Properties can be used to delay initialization of a resource until the moment it is first referenced. Por exemplo:For example:

using System.IO;

public class Console
{
    private static TextReader reader;
    private static TextWriter writer;
    private static TextWriter error;

    public static TextReader In {
        get {
            if (reader == null) {
                reader = new StreamReader(Console.OpenStandardInput());
            }
            return reader;
        }
    }

    public static TextWriter Out {
        get {
            if (writer == null) {
                writer = new StreamWriter(Console.OpenStandardOutput());
            }
            return writer;
        }
    }

    public static TextWriter Error {
        get {
            if (error == null) {
                error = new StreamWriter(Console.OpenStandardError());
            }
            return error;
        }
    }
}

O Console classe contém três propriedades: In, Out, e Error, que representam a entrada padrão, saída e dispositivos de erro, respectivamente.The Console class contains three properties, In, Out, and Error, that represent the standard input, output, and error devices, respectively. Ao expor esses membros como propriedades, o Console classe pode atrasar sua inicialização até que eles são realmente usados.By exposing these members as properties, the Console class can delay their initialization until they are actually used. Por exemplo, após a primeira referenciando o Out propriedade, como emFor example, upon first referencing the Out property, as in

Console.Out.WriteLine("hello, world");

subjacente TextWriter para o dispositivo de saída é criado.the underlying TextWriter for the output device is created. Porém, se o aplicativo não faz referência à In e Error propriedades, em seguida, não há objetos são criados para esses dispositivos.But if the application makes no reference to the In and Error properties, then no objects are created for those devices.

Propriedades implementadas automaticamenteAutomatically implemented properties

Uma propriedade implementada automaticamente (ou auto-propriedade de forma abreviada), é uma propriedade de não-externo não abstrata com corpos de acessador somente-e-vírgula.An automatically implemented property (or auto-property for short), is a non-abstract non-extern property with semicolon-only accessor bodies. Propriedades automáticas devem ter um acessador get e, opcionalmente, podem ter um acessador set.Auto-properties must have a get accessor and can optionally have a set accessor.

Quando uma propriedade é especificada como uma propriedade implementada automaticamente, um campo oculto existente está automaticamente disponível para a propriedade e os acessadores são implementados para ler e gravar a esse campo existente.When a property is specified as an automatically implemented property, a hidden backing field is automatically available for the property, and the accessors are implemented to read from and write to that backing field. Se a propriedade automática não possui nenhum acessador set, o campo de suporte é considerado readonly (campos somente leitura).If the auto-property has no set accessor, the backing field is considered readonly (Readonly fields). Assim como um readonly campo, uma propriedade de automática apenas de getter também pode ser atribuída a no corpo de um construtor da classe delimitadora.Just like a readonly field, a getter-only auto-property can also be assigned to in the body of a constructor of the enclosing class. Essa atribuição atribui diretamente para o campo de suporte da propriedade somente leitura.Such an assignment assigns directly to the readonly backing field of the property.

Uma propriedade automática, opcionalmente, pode ter um property_initializer, que é aplicado diretamente ao campo de suporte como um variable_initializer (inicializadores de variável) .An auto-property may optionally have a property_initializer, which is applied directly to the backing field as a variable_initializer (Variable initializers).

O exemplo a seguir:The following example:

public class Point {
    public int X { get; set; } = 0;
    public int Y { get; set; } = 0;
}

é equivalente à declaração a seguir:is equivalent to the following declaration:

public class Point {
    private int __x = 0;
    private int __y = 0;
    public int X { get { return __x; } set { __x = value; } }
    public int Y { get { return __y; } set { __y = value; } }
}

O exemplo a seguir:The following example:

public class ReadOnlyPoint
{
    public int X { get; }
    public int Y { get; }
    public ReadOnlyPoint(int x, int y) { X = x; Y = y; }
}

é equivalente à declaração a seguir:is equivalent to the following declaration:

public class ReadOnlyPoint
{
    private readonly int __x;
    private readonly int __y;
    public int X { get { return __x; } }
    public int Y { get { return __y; } }
    public ReadOnlyPoint(int x, int y) { __x = x; __y = y; }
}

Observe que as atribuições para o campo somente leitura são legais, porque eles ocorrem dentro do construtor.Notice that the assignments to the readonly field are legal, because they occur within the constructor.

AcessibilidadeAccessibility

Se tiver um acessador de um accessor_modifier, o domínio de acessibilidade (domínios acessibilidade) do acessador é determinado usando a acessibilidade declarada do accessor_modifier .If an accessor has an accessor_modifier, the accessibility domain (Accessibility domains) of the accessor is determined using the declared accessibility of the accessor_modifier. Se um acessador não tem um accessor_modifier, o domínio de acessibilidade do acessador é determinado com base a acessibilidade declarada de propriedade ou indexador.If an accessor does not have an accessor_modifier, the accessibility domain of the accessor is determined from the declared accessibility of the property or indexer.

A presença de um accessor_modifier nunca afeta a pesquisa de membro (operadores) ou resolução de sobrecarga (resolução de sobrecarga).The presence of an accessor_modifier never affects member lookup (Operators) or overload resolution (Overload resolution). Os modificadores de propriedade ou indexador sempre determinam qual propriedade ou indexador está vinculado, independentemente do contexto do acesso.The modifiers on the property or indexer always determine which property or indexer is bound to, regardless of the context of the access.

Depois que uma determinada propriedade ou indexador tiver sido selecionado, os domínios de acessibilidade dos acessadores específicos envolvidos são usados para determinar se esse uso é válido:Once a particular property or indexer has been selected, the accessibility domains of the specific accessors involved are used to determine if that usage is valid:

No exemplo a seguir, a propriedade A.Text está oculto pela propriedade B.Text, mesmo em contextos em que apenas o set acessador é chamado.In the following example, the property A.Text is hidden by the property B.Text, even in contexts where only the set accessor is called. Por outro lado, a propriedade B.Count não é acessível a classe M, portanto, a propriedade acessível A.Count é usado em vez disso.In contrast, the property B.Count is not accessible to class M, so the accessible property A.Count is used instead.

class A
{
    public string Text {
        get { return "hello"; }
        set { }
    }

    public int Count {
        get { return 5; }
        set { }
    }
}

class B: A
{
    private string text = "goodbye"; 
    private int count = 0;

    new public string Text {
        get { return text; }
        protected set { text = value; }
    }

    new protected int Count { 
        get { return count; }
        set { count = value; }
    }
}

class M
{
    static void Main() {
        B b = new B();
        b.Count = 12;             // Calls A.Count set accessor
        int i = b.Count;          // Calls A.Count get accessor
        b.Text = "howdy";         // Error, B.Text set accessor not accessible
        string s = b.Text;        // Calls B.Text get accessor
    }
}

Um acessador que é usado para implementar uma interface não pode ter um accessor_modifier.An accessor that is used to implement an interface may not have an accessor_modifier. Se apenas um acessador é usado para implementar uma interface, o outro acessador pode ser declarado com um accessor_modifier:If only one accessor is used to implement an interface, the other accessor may be declared with an accessor_modifier:

public interface I
{
    string Prop { get; }
}

public class C: I
{
    public Prop {
        get { return "April"; }       // Must not have a modifier here
        internal set {...}            // Ok, because I.Prop has no set accessor
    }
}

Acessadores de propriedade abstrata, substituição e virtuais, seladoVirtual, sealed, override, and abstract property accessors

Um virtual declaração de propriedade que especifica que os acessadores da propriedade são virtuais.A virtual property declaration specifies that the accessors of the property are virtual. O virtual modificador se aplica a ambos os acessadores de uma propriedade de leitura / gravação — não é possível apenas um acessador de uma propriedade de leitura / gravação seja virtual.The virtual modifier applies to both accessors of a read-write property—it is not possible for only one accessor of a read-write property to be virtual.

Um abstract declaração de propriedade especifica que os acessadores da propriedade são virtuais, mas não fornece uma implementação real dos acessadores.An abstract property declaration specifies that the accessors of the property are virtual, but does not provide an actual implementation of the accessors. Em vez disso, as classes derivadas não abstratas devem fornecer sua própria implementação para os acessadores, substituindo a propriedade.Instead, non-abstract derived classes are required to provide their own implementation for the accessors by overriding the property. Como um acessador de uma declaração de propriedade abstrata não fornece nenhuma implementação real, sua accessor_body consiste apenas em um ponto e vírgula.Because an accessor for an abstract property declaration provides no actual implementation, its accessor_body simply consists of a semicolon.

Uma declaração de propriedade que inclui ambos os abstract e override modificadores Especifica que a propriedade é abstrata e substitui uma propriedade base.A property declaration that includes both the abstract and override modifiers specifies that the property is abstract and overrides a base property. Os acessadores de tal propriedade também são abstratos.The accessors of such a property are also abstract.

Declarações de propriedade abstrata são permitidas apenas em classes abstratas (classes abstratas). Os acessadores de uma propriedade herdada de virtual podem ser substituídos em uma classe derivada incluindo uma declaração de propriedade que especifica um override diretiva.Abstract property declarations are only permitted in abstract classes (Abstract classes).The accessors of an inherited virtual property can be overridden in a derived class by including a property declaration that specifies an override directive. Isso é conhecido como um substituindo a declaração de propriedade.This is known as an overriding property declaration. Uma declaração de propriedade de substituição não declara uma nova propriedade.An overriding property declaration does not declare a new property. Em vez disso, ele simplesmente é especialista as implementações de acessadores de uma propriedade virtual existente.Instead, it simply specializes the implementations of the accessors of an existing virtual property.

Uma declaração de propriedade de substituição deve especificar o exato mesmo modificadores de acessibilidade, o tipo e o nome que a propriedade herdada.An overriding property declaration must specify the exact same accessibility modifiers, type, and name as the inherited property. Se a propriedade herdada tiver apenas um único acessador (ou seja, se a propriedade herdada for somente leitura ou somente gravação), a propriedade de substituição deve incluir somente o acessador.If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property must include only that accessor. Se a propriedade herdada inclui ambos os acessadores (ou seja, se a propriedade herdada for leitura / gravação), a propriedade de substituição pode incluir um único acessador ou ambos os acessadores.If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors.

Uma declaração de propriedade de substituição pode incluir o sealed modificador.An overriding property declaration may include the sealed modifier. Uso desse modificador impede que uma classe derivada ainda mais substituindo a propriedade.Use of this modifier prevents a derived class from further overriding the property. Os acessadores de uma propriedade lacrado também são lacrados.The accessors of a sealed property are also sealed.

Exceto pelas diferenças na declaração e chamada de sintaxe, substituição sealed, virtual e acessadores abstratos se comporta exatamente como virtual, selada, substituição e métodos abstratos.Except for differences in declaration and invocation syntax, virtual, sealed, override, and abstract accessors behave exactly like virtual, sealed, override and abstract methods. Especificamente, as regras descritas em métodos virtuais, substituir métodos, lacrados métodos, e métodos abstratos se aplicam como se acessadores eram os métodos de um formulário correspondente:Specifically, the rules described in Virtual methods, Override methods, Sealed methods, and Abstract methods apply as if accessors were methods of a corresponding form:

  • Um get acessador corresponde a um método sem parâmetros com um valor de retorno do tipo de propriedade e os modificadores mesmos que a propriedade recipiente.A get accessor corresponds to a parameterless method with a return value of the property type and the same modifiers as the containing property.
  • Um set acessador corresponde a um método com um parâmetro de valor único de tipo de propriedade, um void retornar o tipo e os modificadores mesmos que a propriedade recipiente.A set accessor corresponds to a method with a single value parameter of the property type, a void return type, and the same modifiers as the containing property.

No exemploIn the example

abstract class A
{
    int y;

    public virtual int X {
        get { return 0; }
    }

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

    public abstract int Z { get; set; }
}

X é uma propriedade somente leitura virtual, Y é uma propriedade de leitura / gravação virtual, e Z é uma propriedade de leitura / gravação abstrata.X is a virtual read-only property, Y is a virtual read-write property, and Z is an abstract read-write property. Porque Z é abstrato, a classe continente A também deve ser declarada como abstrata.Because Z is abstract, the containing class A must also be declared abstract.

Uma classe que deriva de A é mostrado abaixo:A class that derives from A is show below:

class B: A
{
    int z;

    public override int X {
        get { return base.X + 1; }
    }

    public override int Y {
        set { base.Y = value < 0? 0: value; }
    }

    public override int Z {
        get { return z; }
        set { z = value; }
    }
}

Aqui, as declarações das X, Y, e Z estão substituindo declarações de propriedade.Here, the declarations of X, Y, and Z are overriding property declarations. Cada declaração de propriedade corresponde exatamente os modificadores de acessibilidade, o tipo e o nome da propriedade herdada correspondente.Each property declaration exactly matches the accessibility modifiers, type, and name of the corresponding inherited property. O get acessador da X e o set acessador de Y usam o base palavra-chave para acessar os acessadores herdados.The get accessor of X and the set accessor of Y use the base keyword to access the inherited accessors. A declaração de Z substitui os dois acessadores abstratos — portanto, não há nenhum membro de função abstract pendentes no B, e B tem permissão para ser uma classe não abstrata.The declaration of Z overrides both abstract accessors—thus, there are no outstanding abstract function members in B, and B is permitted to be a non-abstract class.

Quando uma propriedade é declarada como um override, qualquer acessadores substituídos devem estar acessíveis ao código de substituição.When a property is declared as an override, any overridden accessors must be accessible to the overriding code. Além disso, a acessibilidade declarada da propriedade ou indexador em si e dos acessadores, deve corresponder do membro substituído e acessadores.In addition, the declared accessibility of both the property or indexer itself, and of the accessors, must match that of the overridden member and accessors. Por exemplo:For example:

public class B
{
    public virtual int P {
        protected set {...}
        get {...}
    }
}

public class D: B
{
    public override int P {
        protected set {...}            // Must specify protected here
        get {...}                      // Must not have a modifier here
    }
}

EventosEvents

Uma evento é um membro que permite que um objeto ou classe para fornecer notificações.An event is a member that enables an object or class to provide notifications. Os clientes podem anexar o código executável para eventos fornecendo manipuladores de eventos.Clients can attach executable code for events by supplying event handlers.

Eventos são declarados usando event_declarations:Events are declared using event_declarations:

event_declaration
    : attributes? event_modifier* 'event' type variable_declarators ';'
    | attributes? event_modifier* 'event' type member_name '{' event_accessor_declarations '}'
    ;

event_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | event_modifier_unsafe
    ;

event_accessor_declarations
    : add_accessor_declaration remove_accessor_declaration
    | remove_accessor_declaration add_accessor_declaration
    ;

add_accessor_declaration
    : attributes? 'add' block
    ;

remove_accessor_declaration
    : attributes? 'remove' block
    ;

Uma event_declaration pode incluir um conjunto de atributos (atributos) e uma combinação válida de as quatro modificadores de acesso (modificadores de acesso ), o new (o novo modificador), static (métodos estáticos e de instância), virtual (métodos virtuais), override (Substituir métodos), sealed (lacrados métodos), abstract (métodos abstratos), e extern (Métodos externos) modificadores.An event_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), static (Static and instance methods), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

Declarações de evento estão sujeitos às mesmas regras de declarações de método (métodos) em relação a combinações válidas de modificadores.Event declarations are subject to the same rules as method declarations (Methods) with regard to valid combinations of modifiers.

O tipo de um evento declaração deve ser um delegate_type (tipos de referência) e que delegate_type deve ter pelo menos como acessível quanto o próprio evento (restrições de acessibilidade).The type of an event declaration must be a delegate_type (Reference types), and that delegate_type must be at least as accessible as the event itself (Accessibility constraints).

Uma declaração de evento pode incluir event_accessor_declarations.An event declaration may include event_accessor_declarations. No entanto, se não existir, para não-externo e eventos de não-abstrata, o compilador fornece-os automaticamente (eventos semelhantes a campo); para eventos de extern, os acessadores são fornecidos externamente.However, if it does not, for non-extern, non-abstract events, the compiler supplies them automatically (Field-like events); for extern events, the accessors are provided externally.

Uma declaração de evento que omite event_accessor_declarations define um ou mais eventos — uma para cada um dos variable_declarators.An event declaration that omits event_accessor_declarations defines one or more events—one for each of the variable_declarators. Os atributos e modificadores que se aplicam a todos os membros declarados, como uma event_declaration.The attributes and modifiers apply to all of the members declared by such an event_declaration.

É um erro de tempo de compilação para um event_declaration de incluir ambas as abstract modificador e delimitado por chaves event_accessor_declarations.It is a compile-time error for an event_declaration to include both the abstract modifier and brace-delimited event_accessor_declarations.

Quando uma declaração de evento inclui um extern modificador, o evento deve ser um evento externo.When an event declaration includes an extern modifier, the event is said to be an external event. Como uma declaração de evento externo fornece nenhuma implementação real, ele é um erro para que ele inclua ambos os extern modificador e event_accessor_declarations.Because an external event declaration provides no actual implementation, it is an error for it to include both the extern modifier and event_accessor_declarations.

É um erro de tempo de compilação para um variable_declarator de uma declaração de evento com um abstract ou external modificador para incluir um variable_initializer.It is a compile-time error for a variable_declarator of an event declaration with an abstract or external modifier to include a variable_initializer.

Um evento pode ser usado como o operando esquerdo do += e -= operadores (atribuição de evento).An event can be used as the left-hand operand of the += and -= operators (Event assignment). Esses operadores são usados, respectivamente, para anexar manipuladores de eventos ou remover manipuladores de eventos de um evento, e os modificadores de acesso do evento de controlam os contextos em que essas operações são permitidas.These operators are used, respectively, to attach event handlers to or to remove event handlers from an event, and the access modifiers of the event control the contexts in which such operations are permitted.

Uma vez que += e -= são as únicas operações que são permitidas em um evento fora do tipo que declara o evento, o código externo podem adicionar e remover manipuladores para um evento, mas não é possível de qualquer outra maneira de obter ou modificar a lista subjacente do evento manipuladores.Since += and -= are the only operations that are permitted on an event outside the type that declares the event, external code can add and remove handlers for an event, but cannot in any other way obtain or modify the underlying list of event handlers.

Em uma operação do formulário x += y ou x -= y, quando x é um evento e a referência ocorre fora do tipo que contém a declaração de x, o resultado da operação tem tipo void (em vez de o tipo de x, com o valor de x após a atribuição).In an operation of the form x += y or x -= y, when x is an event and the reference takes place outside the type that contains the declaration of x, the result of the operation has type void (as opposed to having the type of x, with the value of x after the assignment). Essa regra proíbe código externo indiretamente examinando o delegado subjacente de um evento.This rule prohibits external code from indirectly examining the underlying delegate of an event.

O exemplo a seguir mostra como os manipuladores de eventos são anexados a instâncias do Button classe:The following example shows how event handlers are attached to instances of the Button class:

public delegate void EventHandler(object sender, EventArgs e);

public class Button: Control
{
    public event EventHandler Click;
}

public class LoginDialog: Form
{
    Button OkButton;
    Button CancelButton;

    public LoginDialog() {
        OkButton = new Button(...);
        OkButton.Click += new EventHandler(OkButtonClick);
        CancelButton = new Button(...);
        CancelButton.Click += new EventHandler(CancelButtonClick);
    }

    void OkButtonClick(object sender, EventArgs e) {
        // Handle OkButton.Click event
    }

    void CancelButtonClick(object sender, EventArgs e) {
        // Handle CancelButton.Click event
    }
}

Aqui, o LoginDialog construtor de instância cria dois Button instâncias e anexa os manipuladores de eventos para o Click eventos.Here, the LoginDialog instance constructor creates two Button instances and attaches event handlers to the Click events.

Eventos semelhantes a campoField-like events

Dentro do texto do programa de classe ou struct que contém a declaração de um evento, determinados eventos podem ser usados como campos.Within the program text of the class or struct that contains the declaration of an event, certain events can be used like fields. Para ser usado dessa forma, um evento não deve ser abstract ou externe não deve incluir explicitamente event_accessor_declarations.To be used in this way, an event must not be abstract or extern, and must not explicitly include event_accessor_declarations. Esse evento pode ser usado em qualquer contexto que permite que um campo.Such an event can be used in any context that permits a field. O campo contém um delegado (delegados) que se refere à lista de manipuladores de eventos que foram adicionados ao evento.The field contains a delegate (Delegates) which refers to the list of event handlers that have been added to the event. Se nenhum manipulador de eventos tiver sido adicionado, o campo contém null.If no event handlers have been added, the field contains null.

No exemploIn the example

public delegate void EventHandler(object sender, EventArgs e);

public class Button: Control
{
    public event EventHandler Click;

    protected void OnClick(EventArgs e) {
        if (Click != null) Click(this, e);
    }

    public void Reset() {
        Click = null;
    }
}

Click é usado como um campo dentro de Button classe.Click is used as a field within the Button class. Como demonstrado no exemplo, o campo pode ser examinado, modificado e usado em expressões de invocação do delegado.As the example demonstrates, the field can be examined, modified, and used in delegate invocation expressions. O OnClick método na Button classe "gera" o Click eventos.The OnClick method in the Button class "raises" the Click event. A noção de gerar um evento é precisamente equivalente a invocar o delegado representado pelo evento — assim, não há constructos de linguagem especial para gerar eventos.The notion of raising an event is precisely equivalent to invoking the delegate represented by the event—thus, there are no special language constructs for raising events. Observe que a invocação de delegado é precedida por uma verificação que garante que o delegado for não nulo.Note that the delegate invocation is preceded by a check that ensures the delegate is non-null.

Fora da declaração do Button classe, o Click membro só pode ser usado no lado esquerdo das += e -= operadores, como emOutside the declaration of the Button class, the Click member can only be used on the left-hand side of the += and -= operators, as in

b.Click += new EventHandler(...);

que anexa um delegado à lista de invocação de Click evento, ewhich appends a delegate to the invocation list of the Click event, and

b.Click -= new EventHandler(...);

remover um delegado da lista de invocação do Click eventos.which removes a delegate from the invocation list of the Click event.

Ao compilar um evento de campo, o compilador automaticamente cria o armazenamento para manter o delegado e cria acessadores para o evento que adicionar ou removem manipuladores de eventos para o campo de delegado.When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field. As operações de adição e remoção são thread-safe e pode (mas não é necessárias) ser feito durante a manutenção do bloqueio (instrução lock) no objeto de recipiente para um evento de instância, ou o objeto de tipo (anônimo expressões de criação do objeto) para um evento estático.The addition and removal operations are thread safe, and may (but are not required to) be done while holding the lock (The lock statement) on the containing object for an instance event, or the type object (Anonymous object creation expressions) for a static event.

Portanto, uma instância declaração de evento do formulário:Thus, an instance event declaration of the form:

class X
{
    public event D Ev;
}

será compilada para algo equivalente a:will be compiled to something equivalent to:

class X
{
    private D __Ev;  // field to hold the delegate

    public event D Ev {
        add {
            /* add the delegate in a thread safe way */
        }

        remove {
            /* remove the delegate in a thread safe way */
        }
    }
}

Dentro da classe X, faz referência às Ev no lado esquerdo das += e -= operadores fazem com que a adicionar e remover acessadores a ser invocado.Within the class X, references to Ev on the left-hand side of the += and -= operators cause the add and remove accessors to be invoked. Todas as outras referências a Ev são compilados para referenciar o campo oculto __Ev em vez disso (acesso de membro).All other references to Ev are compiled to reference the hidden field __Ev instead (Member access). O nome "__Ev" é arbitrário; o campo oculto pode ter qualquer nome ou sem nome em todos os.The name "__Ev" is arbitrary; the hidden field could have any name or no name at all.

Acessadores de eventosEvent accessors

Declarações de evento normalmente omitir event_accessor_declarations, como no Button exemplo acima.Event declarations typically omit event_accessor_declarations, as in the Button example above. Uma situação para fazer o tema envolve o caso em que o custo de armazenamento de um campo por evento não é aceitável.One situation for doing so involves the case in which the storage cost of one field per event is not acceptable. Nesses casos, uma classe pode incluir event_accessor_declarations e usar um mecanismo privado para armazenar a lista de manipuladores de eventos.In such cases, a class can include event_accessor_declarations and use a private mechanism for storing the list of event handlers.

O event_accessor_declarations de um evento, especifique as instruções executáveis associadas ao adicionar e remover manipuladores de eventos.The event_accessor_declarations of an event specify the executable statements associated with adding and removing event handlers.

As declarações de acessador consistem em uma add_accessor_declaration e uma remove_accessor_declaration.The accessor declarations consist of an add_accessor_declaration and a remove_accessor_declaration. Cada declaração de acessador consiste o token add ou remove seguido por um bloco.Each accessor declaration consists of the token add or remove followed by a block. O bloco associado com um add_accessor_declaration Especifica as instruções para executar quando um manipulador de eventos é adicionado e o bloco associado com um remove_accessor_declaration Especifica as instruções para executar quando um manipulador de eventos é removido.The block associated with an add_accessor_declaration specifies the statements to execute when an event handler is added, and the block associated with a remove_accessor_declaration specifies the statements to execute when an event handler is removed.

Cada add_accessor_declaration e remove_accessor_declaration corresponde a um método com um parâmetro de valor único do tipo de evento e um void tipo de retorno.Each add_accessor_declaration and remove_accessor_declaration corresponds to a method with a single value parameter of the event type and a void return type. O parâmetro implícito de um acessador de evento é chamado value.The implicit parameter of an event accessor is named value. Quando um evento é usado em uma atribuição de evento, o acessador de evento apropriado é usado.When an event is used in an event assignment, the appropriate event accessor is used. Especificamente, se for o operador de atribuição += acessador adicionar é usado, e se o operador de atribuição é -= , o acessador de remoção será usado.Specifically, if the assignment operator is += then the add accessor is used, and if the assignment operator is -= then the remove accessor is used. Em ambos os casos, o operando à direita do operador de atribuição é usado como o argumento para o acessador do evento.In either case, the right-hand operand of the assignment operator is used as the argument to the event accessor. O bloco de um add_accessor_declaration ou um remove_accessor_declaration devem obedecer às regras para void métodos descritos corpo do método.The block of an add_accessor_declaration or a remove_accessor_declaration must conform to the rules for void methods described in Method body. Em particular, return instruções em tal um bloco não são permitidas para especificar uma expressão.In particular, return statements in such a block are not permitted to specify an expression.

Uma vez que um acessador de evento implicitamente tem um parâmetro chamado value, ele é um erro de tempo de compilação para um local constante ou variável declarada em um acessador de evento esse nome.Since an event accessor implicitly has a parameter named value, it is a compile-time error for a local variable or constant declared in an event accessor to have that name.

No exemploIn the example

class Control: Component
{
    // Unique keys for events
    static readonly object mouseDownEventKey = new object();
    static readonly object mouseUpEventKey = new object();

    // Return event handler associated with key
    protected Delegate GetEventHandler(object key) {...}

    // Add event handler associated with key
    protected void AddEventHandler(object key, Delegate handler) {...}

    // Remove event handler associated with key
    protected void RemoveEventHandler(object key, Delegate handler) {...}

    // MouseDown event
    public event MouseEventHandler MouseDown {
        add { AddEventHandler(mouseDownEventKey, value); }
        remove { RemoveEventHandler(mouseDownEventKey, value); }
    }

    // MouseUp event
    public event MouseEventHandler MouseUp {
        add { AddEventHandler(mouseUpEventKey, value); }
        remove { RemoveEventHandler(mouseUpEventKey, value); }
    }

    // Invoke the MouseUp event
    protected void OnMouseUp(MouseEventArgs args) {
        MouseEventHandler handler; 
        handler = (MouseEventHandler)GetEventHandler(mouseUpEventKey);
        if (handler != null)
            handler(this, args);
    }
}

o Control classe implementa um mecanismo de armazenamento interno para eventos.the Control class implements an internal storage mechanism for events. O AddEventHandler método associa um valor de delegado com uma chave, o GetEventHandler método retorna o delegado atualmente associado a uma chave e o RemoveEventHandler método Remove um delegado como um manipulador de eventos para o evento especificado.The AddEventHandler method associates a delegate value with a key, the GetEventHandler method returns the delegate currently associated with a key, and the RemoveEventHandler method removes a delegate as an event handler for the specified event. Presumivelmente, o mecanismo de armazenamento subjacente foi projetado, de modo que não há nenhum custo para associar um null delegar o valor com uma chave e, portanto, os eventos sem tratamento não consumam nenhum armazenamento.Presumably, the underlying storage mechanism is designed such that there is no cost for associating a null delegate value with a key, and thus unhandled events consume no storage.

Eventos estáticos e de instânciaStatic and instance events

Quando uma declaração de evento inclui um static modificador, o evento deve ser um evento estático.When an event declaration includes a static modifier, the event is said to be a static event. Quando nenhum static modificador estiver presente, o evento deve ser um eventos de instância.When no static modifier is present, the event is said to be an instance event.

Um evento estático não está associado uma instância específica e é um erro de tempo de compilação para se referir a this nos acessadores de um evento estático.A static event is not associated with a specific instance, and it is a compile-time error to refer to this in the accessors of a static event.

Um evento de instância está associado uma determinada instância de uma classe, e essa instância pode ser acessada como this (esse acesso) nos acessadores de evento.An instance event is associated with a given instance of a class, and this instance can be accessed as this (This access) in the accessors of that event.

Quando um evento é referenciado em uma member_access (acesso de membro) do formulário E.M, se M é um evento estático, E deve indicar um tipo que contém Me se M é um evento de instância, E preciso marcar uma instância de um tipo que contém M.When an event is referenced in a member_access (Member access) of the form E.M, if M is a static event, E must denote a type containing M, and if M is an instance event, E must denote an instance of a type containing M.

As diferenças entre static e membros de instância são discutidos mais detalhadamente em membros estáticos e de instância.The differences between static and instance members are discussed further in Static and instance members.

Acessadores de evento abstrato, substituição e virtuais, seladoVirtual, sealed, override, and abstract event accessors

Um virtual declaração de evento especifica que os acessadores de evento são virtuais.A virtual event declaration specifies that the accessors of that event are virtual. O virtual modificador se aplica a ambos os acessadores de um evento.The virtual modifier applies to both accessors of an event.

Um abstract declaração de evento especifica que os acessadores do evento são virtuais, mas não fornece uma implementação real dos acessadores.An abstract event declaration specifies that the accessors of the event are virtual, but does not provide an actual implementation of the accessors. Em vez disso, as classes derivadas não abstratas devem fornecer sua própria implementação para os acessadores, substituindo o evento.Instead, non-abstract derived classes are required to provide their own implementation for the accessors by overriding the event. Como uma declaração de evento abstrata não fornece nenhuma implementação real, ele não pode fornecer delimitada por chaves event_accessor_declarations.Because an abstract event declaration provides no actual implementation, it cannot provide brace-delimited event_accessor_declarations.

Uma declaração de evento que inclui ambos os abstract e override modificadores Especifica que o evento é abstrato e substitui um evento de base.An event declaration that includes both the abstract and override modifiers specifies that the event is abstract and overrides a base event. Os acessadores de um evento também são abstratos.The accessors of such an event are also abstract.

Declarações de evento abstrato são permitidas apenas em classes abstratas (classes abstratas).Abstract event declarations are only permitted in abstract classes (Abstract classes).

Os acessadores de um evento virtual herdado podem ser substituídos em uma classe derivada incluindo uma declaração de evento que especifica um override modificador.The accessors of an inherited virtual event can be overridden in a derived class by including an event declaration that specifies an override modifier. Isso é conhecido como um substituindo a declaração de evento.This is known as an overriding event declaration. Uma declaração de evento de substituição não declara um novo evento.An overriding event declaration does not declare a new event. Em vez disso, ele simplesmente é especialista as implementações de acessadores de um evento virtual existente.Instead, it simply specializes the implementations of the accessors of an existing virtual event.

Uma declaração de evento de substituição deve especificar o exato mesmo modificadores de acessibilidade, o tipo e o nome que o evento substituído.An overriding event declaration must specify the exact same accessibility modifiers, type, and name as the overridden event.

Uma declaração de evento de substituição pode incluir o sealed modificador.An overriding event declaration may include the sealed modifier. Uso desse modificador impede que uma classe derivada ainda mais a substituição de evento.Use of this modifier prevents a derived class from further overriding the event. Os acessadores de um evento lacrado também são lacrados.The accessors of a sealed event are also sealed.

É um erro de tempo de compilação para uma declaração de evento de substituição incluir um new modificador.It is a compile-time error for an overriding event declaration to include a new modifier.

Exceto pelas diferenças na declaração e chamada de sintaxe, substituição sealed, virtual e acessadores abstratos se comporta exatamente como virtual, selada, substituição e métodos abstratos.Except for differences in declaration and invocation syntax, virtual, sealed, override, and abstract accessors behave exactly like virtual, sealed, override and abstract methods. Especificamente, as regras descritas em métodos virtuais, substituir métodos, lacrados métodos, e métodos abstratos se aplicam como se acessadores eram os métodos de um formulário correspondente.Specifically, the rules described in Virtual methods, Override methods, Sealed methods, and Abstract methods apply as if accessors were methods of a corresponding form. Cada acessador corresponde a um método com um parâmetro de valor único de tipo de evento, um void retornar o tipo e os modificadores mesmos que o evento recipiente.Each accessor corresponds to a method with a single value parameter of the event type, a void return type, and the same modifiers as the containing event.

IndexadoresIndexers

Uma indexador é um membro que permite que um objeto a serem indexados da mesma forma como uma matriz.An indexer is a member that enables an object to be indexed in the same way as an array. Indexadores são declarados usando indexer_declarations:Indexers are declared using indexer_declarations:

indexer_declaration
    : attributes? indexer_modifier* indexer_declarator indexer_body
    ;

indexer_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | indexer_modifier_unsafe
    ;

indexer_declarator
    : type 'this' '[' formal_parameter_list ']'
    | type interface_type '.' 'this' '[' formal_parameter_list ']'
    ;

indexer_body
    : '{' accessor_declarations '}' 
    | '=>' expression ';'
    ;

Uma indexer_declaration pode incluir um conjunto de atributos (atributos) e uma combinação válida de as quatro modificadores de acesso (modificadores de acesso ), o new (o novo modificador), virtual (métodos virtuais), override (substituir métodos ), sealed (Lacrados métodos), abstract (métodos abstratos), e extern (métodos externos) modificadores.An indexer_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

Declarações de indexador estão sujeitos às mesmas regras de declarações de método (métodos) em relação a combinações válidas de modificadores, com a exceção de que o modificador estático não é permitida em uma declaração do indexador.Indexer declarations are subject to the same rules as method declarations (Methods) with regard to valid combinations of modifiers, with the one exception being that the static modifier is not permitted on an indexer declaration.

Os modificadores virtual, override, e abstract são mutuamente exclusivos, exceto em um caso.The modifiers virtual, override, and abstract are mutually exclusive except in one case. O abstract e override modificadores podem ser usados juntos para que um indexador abstrato pode substituir um virtual.The abstract and override modifiers may be used together so that an abstract indexer can override a virtual one.

O tipo de um indexador declaração especifica o tipo de elemento do indexador introduzido por declaração.The type of an indexer declaration specifies the element type of the indexer introduced by the declaration. A menos que o indexador é uma implementação de membro de interface explícita, o tipo é seguido da palavra-chave this.Unless the indexer is an explicit interface member implementation, the type is followed by the keyword this. Para uma implementação de membro de interface explícita, o tipo é seguido por um interface_type, um "." e a palavra-chave this.For an explicit interface member implementation, the type is followed by an interface_type, a ".", and the keyword this. Ao contrário de outros membros, os indexadores não tem nomes definidos pelo usuário.Unlike other members, indexers do not have user-defined names.

O formal_parameter_list Especifica os parâmetros do indexador.The formal_parameter_list specifies the parameters of the indexer. Lista de parâmetros formais de um indexador corresponde de um método (parâmetros de método), exceto que deve ser especificado pelo menos um parâmetro e que o ref e out modificadores de parâmetro não são permitidos. .The formal parameter list of an indexer corresponds to that of a method (Method parameters), except that at least one parameter must be specified, and that the ref and out parameter modifiers are not permitted.

O tipo de um indexador e cada um dos tipos referenciados nas formal_parameter_list deve ser pelo menos tão acessíveis quanto o próprio indexador (restrições de acessibilidade).The type of an indexer and each of the types referenced in the formal_parameter_list must be at least as accessible as the indexer itself (Accessibility constraints).

Uma indexer_body qualquer um pode consistir de uma corpo do acessador ou uma corpo da expressão.An indexer_body may either consist of an accessor body or an expression body. Em um corpo de acessador accessor_declarations, que deve ser colocada em "{"e"}" tokens, declare acessadores (acessadores) da propriedade.In an accessor body, accessor_declarations, which must be enclosed in "{" and "}" tokens, declare the accessors (Accessors) of the property. Os acessadores de especificam as instruções executáveis associadas com a leitura e gravação de propriedade.The accessors specify the executable statements associated with reading and writing the property.

Um corpo de expressão consiste em "=>" seguido por uma expressão E e um ponto e vírgula é exatamente equivalente para o corpo da instrução { get { return E; } }e pode, portanto, apenas ser usado para especificar indexadores somente getter onde está o resultado do getter fornecido por uma única expressão.An expression body consisting of "=>" followed by an expression E and a semicolon is exactly equivalent to the statement body { get { return E; } }, and can therefore only be used to specify getter-only indexers where the result of the getter is given by a single expression.

Embora a sintaxe para acessar um elemento do indexador é o mesmo que para um elemento de matriz, um elemento do indexador não é classificado como uma variável.Even though the syntax for accessing an indexer element is the same as that for an array element, an indexer element is not classified as a variable. Assim, não é possível passar um elemento do indexador como um ref ou out argumento.Thus, it is not possible to pass an indexer element as a ref or out argument.

Lista de parâmetros formais de um indexador define a assinatura (assinaturas e sobrecarga) do indexador.The formal parameter list of an indexer defines the signature (Signatures and overloading) of the indexer. Especificamente, a assinatura de um indexador consiste em número e tipos de seus parâmetros formais.Specifically, the signature of an indexer consists of the number and types of its formal parameters. O tipo de elemento e os nomes dos parâmetros formais não fazem parte da assinatura do indexador.The element type and names of the formal parameters are not part of an indexer's signature.

A assinatura de um indexador deve ser diferente das assinaturas de todos os outros indexadores declarados na mesma classe.The signature of an indexer must differ from the signatures of all other indexers declared in the same class.

Indexadores e propriedades são muito semelhantes em conceito, mas diferem das seguintes maneiras:Indexers and properties are very similar in concept, but differ in the following ways:

  • Uma propriedade é identificada por seu nome, enquanto um indexador é identificado por sua assinatura.A property is identified by its name, whereas an indexer is identified by its signature.
  • Uma propriedade é acessada por meio de um simple_name (nomes simples) ou uma member_access (acesso de membro), enquanto um indexador elemento é acessado por meio de um element_access (acesso ao indexador).A property is accessed through a simple_name (Simple names) or a member_access (Member access), whereas an indexer element is accessed through an element_access (Indexer access).
  • Uma propriedade pode ser um static membro, enquanto um indexador é sempre um membro de instância.A property can be a static member, whereas an indexer is always an instance member.
  • Um get acessador de uma propriedade corresponde a um método sem parâmetros, enquanto um get acessador de um indexador corresponde a um método com a mesma lista de parâmetro formal que o indexador.A get accessor of a property corresponds to a method with no parameters, whereas a get accessor of an indexer corresponds to a method with the same formal parameter list as the indexer.
  • Um set acessador de uma propriedade corresponde a um método com um parâmetro único chamado value, enquanto um set acessador de um indexador corresponde a um método com a mesma lista de parâmetro formal que o indexador, além de um parâmetro adicional chamado value.A set accessor of a property corresponds to a method with a single parameter named value, whereas a set accessor of an indexer corresponds to a method with the same formal parameter list as the indexer, plus an additional parameter named value.
  • É um erro de tempo de compilação para um acessador de indexador declarar uma variável local com o mesmo nome como um parâmetro de indexador.It is a compile-time error for an indexer accessor to declare a local variable with the same name as an indexer parameter.
  • Em uma declaração de propriedade de substituição, a propriedade herdada é acessada usando a sintaxe base.P, onde P é o nome da propriedade.In an overriding property declaration, the inherited property is accessed using the syntax base.P, where P is the property name. Em uma declaração de indexador de substituição, o indexador herdado é acessado usando a sintaxe base[E], onde E é uma lista separada por vírgulas de expressões.In an overriding indexer declaration, the inherited indexer is accessed using the syntax base[E], where E is a comma separated list of expressions.
  • Não há nenhum conceito de um "indexador implementado automaticamente".There is no concept of an "automatically implemented indexer". É um erro ter um indexador não-abstrata, não externa com acessadores de ponto e vírgula.It is an error to have a non-abstract, non-external indexer with semicolon accessors.

Além dessas diferenças, todas as regras definidas em acessadores e implementadas automaticamente propriedades se aplicam a acessadores de indexador, bem como para acessadores de propriedade.Aside from these differences, all rules defined in Accessors and Automatically implemented properties apply to indexer accessors as well as to property accessors.

Quando uma declaração de indexador inclui um extern modificador, o indexador é considerado uma indexador externo.When an indexer declaration includes an extern modifier, the indexer is said to be an external indexer. Como uma declaração de indexador externo não fornece nenhuma implementação real, cada um dos seus accessor_declarations consiste em um ponto e vírgula.Because an external indexer declaration provides no actual implementation, each of its accessor_declarations consists of a semicolon.

O exemplo a seguir declara um BitArray classe que implementa um indexador para acessar os bits individuais na matriz de bits.The example below declares a BitArray class that implements an indexer for accessing the individual bits in the bit array.

using System;

class BitArray
{
    int[] bits;
    int length;

    public BitArray(int length) {
        if (length < 0) throw new ArgumentException();
        bits = new int[((length - 1) >> 5) + 1];
        this.length = length;
    }

    public int Length {
        get { return length; }
    }

    public bool this[int index] {
        get {
            if (index < 0 || index >= length) {
                throw new IndexOutOfRangeException();
            }
            return (bits[index >> 5] & 1 << index) != 0;
        }
        set {
            if (index < 0 || index >= length) {
                throw new IndexOutOfRangeException();
            }
            if (value) {
                bits[index >> 5] |= 1 << index;
            }
            else {
                bits[index >> 5] &= ~(1 << index);
            }
        }
    }
}

Uma instância da BitArray classe consome significativamente menos memória do que um correspondente bool[] (já que cada valor do primeiro ocupa apenas um bit em vez do último de um byte), mas permite que as mesmas operações que um bool[].An instance of the BitArray class consumes substantially less memory than a corresponding bool[] (since each value of the former occupies only one bit instead of the latter's one byte), but it permits the same operations as a bool[].

O seguinte CountPrimes classe usa um BitArray e o algoritmo de "sieve" clássico para calcular o número de números primos entre 1 e um máximo de determinado:The following CountPrimes class uses a BitArray and the classical "sieve" algorithm to compute the number of primes between 1 and a given maximum:

class CountPrimes
{
    static int Count(int max) {
        BitArray flags = new BitArray(max + 1);
        int count = 1;
        for (int i = 2; i <= max; i++) {
            if (!flags[i]) {
                for (int j = i * 2; j <= max; j += i) flags[j] = true;
                count++;
            }
        }
        return count;
    }

    static void Main(string[] args) {
        int max = int.Parse(args[0]);
        int count = Count(max);
        Console.WriteLine("Found {0} primes between 1 and {1}", count, max);
    }
}

Observe que a sintaxe para acessar os elementos do BitArray é exatamente a mesma usada para um bool[].Note that the syntax for accessing elements of the BitArray is precisely the same as for a bool[].

O exemplo a seguir mostra uma classe de 26 * 10 grade que tem um indexador com dois parâmetros.The following example shows a 26 * 10 grid class that has an indexer with two parameters. O primeiro parâmetro deve ser uma letra maiuscula ou letra minúscula no intervalo A-Z e a segunda é necessário para ser um número inteiro no intervalo de 0 a 9.The first parameter is required to be an upper- or lowercase letter in the range A-Z, and the second is required to be an integer in the range 0-9.

using System;

class Grid
{
    const int NumRows = 26;
    const int NumCols = 10;

    int[,] cells = new int[NumRows, NumCols];

    public int this[char c, int col] {
        get {
            c = Char.ToUpper(c);
            if (c < 'A' || c > 'Z') {
                throw new ArgumentException();
            }
            if (col < 0 || col >= NumCols) {
                throw new IndexOutOfRangeException();
            }
            return cells[c - 'A', col];
        }

        set {
            c = Char.ToUpper(c);
            if (c < 'A' || c > 'Z') {
                throw new ArgumentException();
            }
            if (col < 0 || col >= NumCols) {
                throw new IndexOutOfRangeException();
            }
            cells[c - 'A', col] = value;
        }
    }
}

Sobrecarga de indexadorIndexer overloading

As regras de resolução de sobrecarga do indexador são descritas em inferência de tipo.The indexer overload resolution rules are described in Type inference.

OperadoresOperators

Uma operador é um membro que define o significado de um operador de expressão que pode ser aplicado a instâncias da classe.An operator is a member that defines the meaning of an expression operator that can be applied to instances of the class. Operadores são declarados usando operator_declarations:Operators are declared using operator_declarations:

operator_declaration
    : attributes? operator_modifier+ operator_declarator operator_body
    ;

operator_modifier
    : 'public'
    | 'static'
    | 'extern'
    | operator_modifier_unsafe
    ;

operator_declarator
    : unary_operator_declarator
    | binary_operator_declarator
    | conversion_operator_declarator
    ;

unary_operator_declarator
    : type 'operator' overloadable_unary_operator '(' type identifier ')'
    ;

overloadable_unary_operator
    : '+' | '-' | '!' | '~' | '++' | '--' | 'true' | 'false'
    ;

binary_operator_declarator
    : type 'operator' overloadable_binary_operator '(' type identifier ',' type identifier ')'
    ;

overloadable_binary_operator
    : '+'   | '-'   | '*'   | '/'   | '%'   | '&'   | '|'   | '^'   | '<<'
    | right_shift | '=='  | '!='  | '>'   | '<'   | '>='  | '<='
    ;

conversion_operator_declarator
    : 'implicit' 'operator' type '(' type identifier ')'
    | 'explicit' 'operator' type '(' type identifier ')'
    ;

operator_body
    : block
    | '=>' expression ';'
    | ';'
    ;

Há três categorias de operadores sobrecarregáveis: Operadores unários (operadores unários), operadores binários (operadores binários) e os operadores de conversão (operadores de conversão).There are three categories of overloadable operators: Unary operators (Unary operators), binary operators (Binary operators), and conversion operators (Conversion operators).

O operator_body é um vírgula, um corpo da instrução ou uma corpo da expressão.The operator_body is either a semicolon, a statement body or an expression body. Um corpo de declaração consiste em uma bloco, que especifica as instruções para executar quando o operador é invocado.A statement body consists of a block, which specifies the statements to execute when the operator is invoked. O bloco deve obedecer às regras para retornar o valor métodos descritos corpo do método.The block must conform to the rules for value-returning methods described in Method body. Consiste em um corpo de expressão => seguido por uma expressão e um ponto e vírgula e denota uma única expressão para executar quando o operador é invocado.An expression body consists of => followed by an expression and a semicolon, and denotes a single expression to perform when the operator is invoked.

Para extern operadores, o operator_body consiste simplesmente em um ponto e vírgula.For extern operators, the operator_body consists simply of a semicolon. Para todos os outros operadores, o operator_body é um corpo do bloco ou um corpo de expressão.For all other operators, the operator_body is either a block body or an expression body.

As seguintes regras se aplicam a todas as declarações de operador:The following rules apply to all operator declarations:

  • Uma declaração do operador deve incluir um public e um static modificador.An operator declaration must include both a public and a static modifier.
  • O parâmetro (s) de um operador deve ser parâmetros de valor (parâmetros de valores).The parameter(s) of an operator must be value parameters (Value parameters). É um erro de tempo de compilação para uma declaração do operador especificar ref ou out parâmetros.It is a compile-time error for an operator declaration to specify ref or out parameters.
  • A assinatura de um operador (operadores unários, operadores binários, operadores de conversão) deve ser diferente das assinaturas de todos os outros operadores declarados no mesma classe.The signature of an operator (Unary operators, Binary operators, Conversion operators) must differ from the signatures of all other operators declared in the same class.
  • Todos os tipos referenciados em uma declaração do operador devem ser pelo menos tão acessíveis quanto o próprio operador (restrições de acessibilidade).All types referenced in an operator declaration must be at least as accessible as the operator itself (Accessibility constraints).
  • É um erro para o mesmo modificador aparecer várias vezes em uma declaração do operador.It is an error for the same modifier to appear multiple times in an operator declaration.

Cada categoria de operador impõe restrições adicionais, conforme descrito nas seções a seguir.Each operator category imposes additional restrictions, as described in the following sections.

Como outros membros, os operadores declarados em uma classe base são herdados por classes derivadas.Like other members, operators declared in a base class are inherited by derived classes. Como declarações de operador sempre exigem a classe ou struct no qual o operador é declarado para participar na assinatura do operador, não é possível que um operador declarado em uma classe derivada ocultar um operador declarado em uma classe base.Because operator declarations always require the class or struct in which the operator is declared to participate in the signature of the operator, it is not possible for an operator declared in a derived class to hide an operator declared in a base class. Portanto, o new modificador nunca é necessária e, portanto, nunca permitido, em uma declaração do operador.Thus, the new modifier is never required, and therefore never permitted, in an operator declaration.

Informações adicionais sobre os operadores unários e binários podem ser encontradas no operadores.Additional information on unary and binary operators can be found in Operators.

Informações adicionais sobre os operadores de conversão podem ser encontradas no conversões definidas pelo usuário.Additional information on conversion operators can be found in User-defined conversions.

Operadores unáriosUnary operators

As seguintes regras se aplicam às declarações de operador unário, onde T indica o tipo de instância da classe ou struct que contém a declaração do operador:The following rules apply to unary operator declarations, where T denotes the instance type of the class or struct that contains the operator declaration:

  • Um unário +, -, !, ou ~ operador deve levar um único parâmetro do tipo T ou T? e pode retornar qualquer tipo.A unary +, -, !, or ~ operator must take a single parameter of type T or T? and can return any type.
  • Um unário ++ ou -- operador deve levar um único parâmetro do tipo T ou T? e deve retornar o mesmo tipo ou um tipo derivado dele.A unary ++ or -- operator must take a single parameter of type T or T? and must return that same type or a type derived from it.
  • Um unário true ou false operador deve levar um único parâmetro do tipo T ou T? e deve retornar tipo bool.A unary true or false operator must take a single parameter of type T or T? and must return type bool.

A assinatura de um operador unário consiste o token de operador (+, -, !, ~, ++, --, true, ou false) e o tipo do parâmetro formal único.The signature of a unary operator consists of the operator token (+, -, !, ~, ++, --, true, or false) and the type of the single formal parameter. O tipo de retorno não é parte de assinatura de um operador unário, nem é o nome do parâmetro formal.The return type is not part of a unary operator's signature, nor is the name of the formal parameter.

O true e false operadores unários exigem declaração por pares.The true and false unary operators require pair-wise declaration. Ocorrerá um erro de tempo de compilação se uma classe declara um destes operadores sem declarar também o outro.A compile-time error occurs if a class declares one of these operators without also declaring the other. O true e false operadores são descritos mais detalhadamente em operadores lógicos condicionais definidos pelo usuário e expressões Boolianas.The true and false operators are described further in User-defined conditional logical operators and Boolean expressions.

O exemplo a seguir mostra uma implementação e uso subsequente de operator ++ para uma classe de vetor de inteiro:The following example shows an implementation and subsequent usage of operator ++ for an integer vector class:

public class IntVector
{
    public IntVector(int length) {...}

    public int Length {...}                 // read-only property

    public int this[int index] {...}        // read-write indexer

    public static IntVector operator ++(IntVector iv) {
        IntVector temp = new IntVector(iv.Length);
        for (int i = 0; i < iv.Length; i++)
            temp[i] = iv[i] + 1;
        return temp;
    }
}

class Test
{
    static void Main() {
        IntVector iv1 = new IntVector(4);    // vector of 4 x 0
        IntVector iv2;

        iv2 = iv1++;    // iv2 contains 4 x 0, iv1 contains 4 x 1
        iv2 = ++iv1;    // iv2 contains 4 x 2, iv1 contains 4 x 2
    }
}

Observe como o método do operador retorna o valor produzido, adicionando 1 ao operando, assim como o incremento de sufixo e operadores de decremento (incremento de sufixo e operadores de decremento) e o incremento de prefixo e de decremento operadores (incremento de prefixo e operadores de decremento).Note how the operator method returns the value produced by adding 1 to the operand, just like the postfix increment and decrement operators (Postfix increment and decrement operators), and the prefix increment and decrement operators (Prefix increment and decrement operators). Ao contrário em C++, esse método precisa não modificar o valor do operando diretamente.Unlike in C++, this method need not modify the value of its operand directly. Na verdade, modificando o valor do operando violar a semântica padrão de operador de incremento de sufixo.In fact, modifying the operand value would violate the standard semantics of the postfix increment operator.

Operadores bináriosBinary operators

As seguintes regras se aplicam às declarações de operador binário, onde T indica o tipo de instância da classe ou struct que contém a declaração do operador:The following rules apply to binary operator declarations, where T denotes the instance type of the class or struct that contains the operator declaration:

  • Um operador de deslocamento não binário deve levar dois parâmetros, pelo menos um dos quais deve ter o tipo T ou T?e pode retornar qualquer tipo.A binary non-shift operator must take two parameters, at least one of which must have type T or T?, and can return any type.
  • Um binário << ou >> operador deve levar dois parâmetros, o primeiro deles deve ser do tipo T ou T? e o segundo dos quais deve ser do tipo int ou int?e pode retornar qualquer tipo.A binary << or >> operator must take two parameters, the first of which must have type T or T? and the second of which must have type int or int?, and can return any type.

A assinatura de um operador binário consiste o token de operador (+, -, *, /, %, &, |, ^, <<, >>, ==, !=, >, <, >=, ou <=) e os tipos dos dois parâmetros formais.The signature of a binary operator consists of the operator token (+, -, *, /, %, &, |, ^, <<, >>, ==, !=, >, <, >=, or <=) and the types of the two formal parameters. O tipo de retorno e os nomes dos parâmetros formais não fazem parte da assinatura de um operador binário.The return type and the names of the formal parameters are not part of a binary operator's signature.

Determinados operadores binários requerem uma declaração por pares.Certain binary operators require pair-wise declaration. Para cada declaração de qualquer operador de um par, deve haver uma declaração correspondente do operador do par.For every declaration of either operator of a pair, there must be a matching declaration of the other operator of the pair. Duas declarações do operador correspondam quando tiverem o mesmo tipo de retorno e o mesmo tipo para cada parâmetro.Two operator declarations match when they have the same return type and the same type for each parameter. Os operadores a seguir exigem uma declaração por pares:The following operators require pair-wise declaration:

  • operator == e operator !=operator == and operator !=
  • operator > e operator <operator > and operator <
  • operator >= e operator <=operator >= and operator <=

Operadores de conversãoConversion operators

Uma declaração do operador de conversão apresenta uma conversão definida pelo usuário (conversões definidas pelo usuário) que amplia as conversões implícitas e explícitas predefinidas.A conversion operator declaration introduces a user-defined conversion (User-defined conversions) which augments the pre-defined implicit and explicit conversions.

Uma declaração do operador de conversão que inclui o implicit palavra-chave introduz uma conversão implícita definidas pelo usuário.A conversion operator declaration that includes the implicit keyword introduces a user-defined implicit conversion. Conversões implícitas podem ocorrer em uma variedade de situações, incluindo as invocações de função de membro, expressões de conversão e atribuições.Implicit conversions can occur in a variety of situations, including function member invocations, cast expressions, and assignments. Isso é descrito posteriormente em conversões implícitas.This is described further in Implicit conversions.

Uma declaração do operador de conversão que inclui o explicit palavra-chave introduz uma conversão explícita definida pelo usuário.A conversion operator declaration that includes the explicit keyword introduces a user-defined explicit conversion. Conversões explícitas podem ocorrer em expressões de conversão e são descritas mais detalhadamente no conversões explícitas.Explicit conversions can occur in cast expressions, and are described further in Explicit conversions.

Um operador de conversão converte de um tipo de fonte, indicado pelo tipo de parâmetro de operador de conversão, para um tipo de destino, indicado pelo tipo de retorno do operador de conversão.A conversion operator converts from a source type, indicated by the parameter type of the conversion operator, to a target type, indicated by the return type of the conversion operator.

Para um tipo de origem especificado S e o tipo de destino T, se S ou T são tipos que permitem valor nulos, deixe S0 e T0 consulte seus tipos base, caso contrário S0 e T0 são igual a S e T , respectivamente.For a given source type S and target type T, if S or T are nullable types, let S0 and T0 refer to their underlying types, otherwise S0 and T0 are equal to S and T respectively. Uma classe ou struct é permitida para declarar uma conversão de um tipo de fonte S para um tipo de destino T somente se todos os itens a seguir forem verdadeiras:A class or struct is permitted to declare a conversion from a source type S to a target type T only if all of the following are true:

  • S0 e T0 são de tipos diferentes.S0 and T0 are different types.
  • Tanto S0 ou T0 é o tipo de classe ou struct em que a declaração do operador ocorre.Either S0 or T0 is the class or struct type in which the operator declaration takes place.
  • Nem S0 nem T0 é um interface_type.Neither S0 nor T0 is an interface_type.
  • Excluindo conversões definidas pelo usuário, uma conversão não existe na S à T ou do T para S.Excluding user-defined conversions, a conversion does not exist from S to T or from T to S.

Para fins dessas regras, qualquer tipo de parâmetros associados S ou T são considerados tipos exclusivos que têm nenhuma relação de herança com outros tipos e quaisquer restrições no tipo desses parâmetros serão ignorados.For the purposes of these rules, any type parameters associated with S or T are considered to be unique types that have no inheritance relationship with other types, and any constraints on those type parameters are ignored.

No exemploIn the example

class C<T> {...}

class D<T>: C<T>
{
    public static implicit operator C<int>(D<T> value) {...}      // Ok
    public static implicit operator C<string>(D<T> value) {...}   // Ok
    public static implicit operator C<T>(D<T> value) {...}        // Error
}

a primeira operátoru duas é permitidas porque, para as finalidades indexadores.3, T e int e string respectivamente são considerados tipos exclusivos sem relação alguma com.the first two operator declarations are permitted because, for the purposes of Indexers.3, T and int and string respectively are considered unique types with no relationship. No entanto, o terceiro operador é um erro, porque C<T> é a classe base de D<T>.However, the third operator is an error because C<T> is the base class of D<T>.

Na segunda regra que segue um operador de conversão deve converter para ou do tipo de classe ou estrutura na qual o operador é declarado.From the second rule it follows that a conversion operator must convert either to or from the class or struct type in which the operator is declared. Por exemplo, é possível para um tipo de classe ou struct C para definir uma conversão de C para int e do int para C, mas não contra int para bool.For example, it is possible for a class or struct type C to define a conversion from C to int and from int to C, but not from int to bool.

Não é possível redefinir diretamente uma conversão predefinida.It is not possible to directly redefine a pre-defined conversion. Assim, os operadores de conversão não são permitidos para converter de ou para o object porque já existem conversões implícitas e explícitas entre object e todos os outros tipos.Thus, conversion operators are not allowed to convert from or to object because implicit and explicit conversions already exist between object and all other types. Da mesma forma, nem a origem ou os tipos de destino de uma conversão podem ser um tipo base dos outros, uma vez que uma conversão, em seguida, seria já existe.Likewise, neither the source nor the target types of a conversion can be a base type of the other, since a conversion would then already exist.

No entanto, é possível declarar operadores em tipos genéricos que, para argumentos de tipo específico, especificam as conversões que já existem como conversões predefinidas.However, it is possible to declare operators on generic types that, for particular type arguments, specify conversions that already exist as pre-defined conversions. No exemploIn the example

struct Convertible<T>
{
    public static implicit operator Convertible<T>(T value) {...}
    public static explicit operator T(Convertible<T> value) {...}
}

Quando digita object é especificado como um argumento de tipo para T, o segundo operador declara uma conversão que já existe (implícito e, portanto, também um valor explícito, existe conversão de qualquer tipo para object).when type object is specified as a type argument for T, the second operator declares a conversion that already exists (an implicit, and therefore also an explicit, conversion exists from any type to type object).

Em casos em que uma conversão predefinida existe entre dois tipos, as conversões definidas pelo usuário entre esses tipos são ignoradas.In cases where a pre-defined conversion exists between two types, any user-defined conversions between those types are ignored. Especificamente:Specifically:

  • Se uma conversão implícita predefinida (conversões implícitas) do tipo S digitar T, todas as conversões definidas por usuário (implícitas ou explícitas) do S para T são ignorados.If a pre-defined implicit conversion (Implicit conversions) exists from type S to type T, all user-defined conversions (implicit or explicit) from S to T are ignored.
  • Se uma conversão explícita predefinida (conversões explícitas) do tipo S digitar T, nenhuma conversão explícita definida pelo usuário do S para T são ignorados.If a pre-defined explicit conversion (Explicit conversions) exists from type S to type T, any user-defined explicit conversions from S to T are ignored. Além disso:Furthermore:

Se T é um tipo de interface, definido pelo usuário conversões implícitas de S para T são ignorados.If T is an interface type, user-defined implicit conversions from S to T are ignored.

Caso contrário, definido pelo usuário conversões implícitas de S para T ainda são consideradas.Otherwise, user-defined implicit conversions from S to T are still considered.

Para todos os tipos, mas object, os operadores são declarados pelo Convertible<T> tipo acima não entram em conflito com conversões predefinidas.For all types but object, the operators declared by the Convertible<T> type above do not conflict with pre-defined conversions. Por exemplo:For example:

void F(int i, Convertible<int> n) {
    i = n;                          // Error
    i = (int)n;                     // User-defined explicit conversion
    n = i;                          // User-defined implicit conversion
    n = (Convertible<int>)i;        // User-defined implicit conversion
}

No entanto, para o tipo object, conversões predefinidas ocultar as conversões definidas pelo usuário em todos os casos, mas um:However, for type object, pre-defined conversions hide the user-defined conversions in all cases but one:

void F(object o, Convertible<object> n) {
    o = n;                         // Pre-defined boxing conversion
    o = (object)n;                 // Pre-defined boxing conversion
    n = o;                         // User-defined implicit conversion
    n = (Convertible<object>)o;    // Pre-defined unboxing conversion
}

Conversões definidas pelo usuário não são permitidas para converter de ou para o interface_types.User-defined conversions are not allowed to convert from or to interface_types. Em particular, essa restrição garante que nenhum transformações definidas pelo usuário ocorram durante a conversão em um interface_typee que uma conversão para um interface_type terá êxito apenas se o objeto Na verdade, que está sendo convertido implementa especificado interface_type.In particular, this restriction ensures that no user-defined transformations occur when converting to an interface_type, and that a conversion to an interface_type succeeds only if the object being converted actually implements the specified interface_type.

A assinatura de um operador de conversão consiste no tipo de origem e o tipo de destino.The signature of a conversion operator consists of the source type and the target type. (Observe que isso é o único formulário de membro para o qual o tipo de retorno participa na assinatura.) O implicit ou explicit classificação de um operador de conversão não é parte da assinatura do operador.(Note that this is the only form of member for which the return type participates in the signature.) The implicit or explicit classification of a conversion operator is not part of the operator's signature. Dessa forma, uma classe ou struct não pode declarar tanto uma implicit e um explicit operador de conversão com os mesmos tipos de origem e destino.Thus, a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types.

Em geral, as conversões implícitas definidas pelo usuário devem ser criadas para nunca lançam exceções e perder informações.In general, user-defined implicit conversions should be designed to never throw exceptions and never lose information. Se uma conversão definida pelo usuário pode gerar exceções (por exemplo, porque o argumento de origem está fora do intervalo) ou perda de informações (por exemplo, descartando os bits de ordem superior) e, em seguida, essa conversão deve ser definida como uma conversão explícita.If a user-defined conversion can give rise to exceptions (for example, because the source argument is out of range) or loss of information (such as discarding high-order bits), then that conversion should be defined as an explicit conversion.

No exemploIn the example

using System;

public struct Digit
{
    byte value;

    public Digit(byte value) {
        if (value < 0 || value > 9) throw new ArgumentException();
        this.value = value;
    }

    public static implicit operator byte(Digit d) {
        return d.value;
    }

    public static explicit operator Digit(byte b) {
        return new Digit(b);
    }
}

a conversão de Digit à byte é implícito porque nunca gera exceções ou perde informações, mas a conversão de byte à Digit é explícito desde Digit pode representar apenas um subconjunto dos possíveis valores de um byte.the conversion from Digit to byte is implicit because it never throws exceptions or loses information, but the conversion from byte to Digit is explicit since Digit can only represent a subset of the possible values of a byte.

Construtores de instânciaInstance constructors

Um construtor de instância é um membro que implementa as ações necessárias para inicializar uma instância de uma classe.An instance constructor is a member that implements the actions required to initialize an instance of a class. Construtores de instância são declaradas usando constructor_declarations:Instance constructors are declared using constructor_declarations:

constructor_declaration
    : attributes? constructor_modifier* constructor_declarator constructor_body
    ;

constructor_modifier
    : 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'extern'
    | constructor_modifier_unsafe
    ;

constructor_declarator
    : identifier '(' formal_parameter_list? ')' constructor_initializer?
    ;

constructor_initializer
    : ':' 'base' '(' argument_list? ')'
    | ':' 'this' '(' argument_list? ')'
    ;

constructor_body
    : block
    | ';'
    ;

Um constructor_declaration pode incluir um conjunto de atributos (atributos), uma combinação válida de as quatro modificadores de acesso (modificadores de acesso ) e uma extern (métodos externos) modificador.A constructor_declaration may include a set of attributes (Attributes), a valid combination of the four access modifiers (Access modifiers), and an extern (External methods) modifier. Uma declaração de construtor não é permitida para incluir o modificador mesmo várias vezes.A constructor declaration is not permitted to include the same modifier multiple times.

O identificador de uma constructor_declarator deve nomear a classe na qual o construtor de instância é declarado.The identifier of a constructor_declarator must name the class in which the instance constructor is declared. Se nenhum outro nome for especificado, ocorrerá um erro de tempo de compilação.If any other name is specified, a compile-time error occurs.

Opcional formal_parameter_list de uma instância do construtor está sujeito às mesmas regras que o formal_parameter_list de um método (métodos).The optional formal_parameter_list of an instance constructor is subject to the same rules as the formal_parameter_list of a method (Methods). Lista de parâmetros formais define a assinatura (assinaturas e sobrecarga) de um construtor de instância e controla o processo pelo qual resolução de sobrecarga (inferência de tipo) seleciona um determinado Construtor de instância em uma invocação.The formal parameter list defines the signature (Signatures and overloading) of an instance constructor and governs the process whereby overload resolution (Type inference) selects a particular instance constructor in an invocation.

Cada um dos tipos referenciados nos formal_parameter_list de uma instância de construtor deve ser pelo menos tão acessíveis quanto o próprio construtor (restrições de acessibilidade).Each of the types referenced in the formal_parameter_list of an instance constructor must be at least as accessible as the constructor itself (Accessibility constraints).

Opcional constructor_initializer Especifica outro construtor de instância para invocar antes de executar as instruções fornecidas na constructor_body desse construtor de instância.The optional constructor_initializer specifies another instance constructor to invoke before executing the statements given in the constructor_body of this instance constructor. Isso é descrito posteriormente em inicializadores de construtor.This is described further in Constructor initializers.

Quando uma declaração de construtor inclui um extern modificador, o construtor deve ser um externo construtor.When a constructor declaration includes an extern modifier, the constructor is said to be an external constructor. Como uma declaração de construtor externo não fornece nenhuma implementação real, sua constructor_body consiste em um ponto e vírgula.Because an external constructor declaration provides no actual implementation, its constructor_body consists of a semicolon. Para todos os outros construtores, o constructor_body consiste em um bloco que especifica as instruções para inicializar uma nova instância da classe.For all other constructors, the constructor_body consists of a block which specifies the statements to initialize a new instance of the class. Isso corresponde exatamente a bloco de um método de instância com um void tipo de retorno (corpo do método).This corresponds exactly to the block of an instance method with a void return type (Method body).

Construtores de instância não são herdadas.Instance constructors are not inherited. Dessa forma, uma classe não tem nenhum construtor de instância que não sejam aqueles realmente declarados na classe.Thus, a class has no instance constructors other than those actually declared in the class. Se uma classe não contiver nenhuma declaração de construtor de instância, um construtor de instância padrão é fornecido automaticamente (1>construtores padrão).If a class contains no instance constructor declarations, a default instance constructor is automatically provided (Default constructors).

Construtores de instância são invocados pelo object_creation_expressions (expressões de criação do objeto) e por meio das constructor_initializers.Instance constructors are invoked by object_creation_expressions (Object creation expressions) and through constructor_initializers.

Inicializadores de construtoresConstructor initializers

Todos os construtores de instância (exceto aqueles para a classe object) implicitamente incluem uma invocação de outro construtor de instância imediatamente anterior a constructor_body.All instance constructors (except those for class object) implicitly include an invocation of another instance constructor immediately before the constructor_body. O construtor para invocar implicitamente é determinado pelo constructor_initializer:The constructor to implicitly invoke is determined by the constructor_initializer:

  • Um inicializador do construtor de instância do formulário base(argument_list) ou base() faz com que um construtor de instância da classe base direta a ser invocado.An instance constructor initializer of the form base(argument_list) or base() causes an instance constructor from the direct base class to be invoked. Esse construtor está selecionado, usando argument_list se estiverem presentes e as regras de resolução de sobrecarga resolução de sobrecarga.That constructor is selected using argument_list if present and the overload resolution rules of Overload resolution. O conjunto de construtores de instância de candidato consiste em todos os construtores de instância acessível contidos na classe base direta ou o construtor padrão (1>construtores padrão), se nenhum construtor de instância é declaradas no classe base direta.The set of candidate instance constructors consists of all accessible instance constructors contained in the direct base class, or the default constructor (Default constructors), if no instance constructors are declared in the direct base class. Se esse conjunto está vazio ou se um construtor de instância única melhor não pode ser identificado, ocorrerá um erro de tempo de compilação.If this set is empty, or if a single best instance constructor cannot be identified, a compile-time error occurs.
  • Um inicializador do construtor de instância do formulário this(argument-list) ou this() faz com que um construtor de instância da classe em si a ser invocado.An instance constructor initializer of the form this(argument-list) or this() causes an instance constructor from the class itself to be invoked. O construtor está selecionado, usando argument_list se estiverem presentes e as regras de resolução de sobrecarga resolução de sobrecarga.The constructor is selected using argument_list if present and the overload resolution rules of Overload resolution. O conjunto de construtores de instância de candidato consiste em todos os construtores de instância acessível declarados na classe em si.The set of candidate instance constructors consists of all accessible instance constructors declared in the class itself. Se esse conjunto está vazio ou se um construtor de instância única melhor não pode ser identificado, ocorrerá um erro de tempo de compilação.If this set is empty, or if a single best instance constructor cannot be identified, a compile-time error occurs. Se uma declaração de construtor de instância inclui um inicializador de construtor que invoca o construtor em si, ocorrerá um erro de tempo de compilação.If an instance constructor declaration includes a constructor initializer that invokes the constructor itself, a compile-time error occurs.

Se um construtor de instância não tem nenhum inicializador de construtor, um inicializador de construtor do formulário base() é fornecido implicitamente.If an instance constructor has no constructor initializer, a constructor initializer of the form base() is implicitly provided. Portanto, uma declaração de construtor de instância do formulárioThus, an instance constructor declaration of the form

C(...) {...}

é exatamente equivalente ais exactly equivalent to

C(...): base() {...}

O escopo dos parâmetros concedida pela formal_parameter_list de um construtor de instância declaração inclui o inicializador do construtor de declaração.The scope of the parameters given by the formal_parameter_list of an instance constructor declaration includes the constructor initializer of that declaration. Portanto, um inicializador de construtor tem permissão para acessar os parâmetros do construtor.Thus, a constructor initializer is permitted to access the parameters of the constructor. Por exemplo:For example:

class A
{
    public A(int x, int y) {}
}

class B: A
{
    public B(int x, int y): base(x + y, x - y) {}
}

Um inicializador de construtor de instância não é possível acessar a instância que está sendo criada.An instance constructor initializer cannot access the instance being created. Portanto, é um erro de tempo de compilação para fazer referência a this em uma expressão de argumento o inicializador do construtor, como é um erro de tempo de compilação para uma expressão de argumento fazer referência a qualquer membro de instância por meio de um simple_name.Therefore it is a compile-time error to reference this in an argument expression of the constructor initializer, as is it a compile-time error for an argument expression to reference any instance member through a simple_name.

Inicializadores de variável de instânciaInstance variable initializers

Quando um construtor de instância não tem nenhum inicializador de construtor, ou ele tem um inicializador de construtor do formulário base(...), esse construtor implicitamente executa as inicializações especificadas pelo variable_initializers de os campos de instância é declarado na sua classe.When an instance constructor has no constructor initializer, or it has a constructor initializer of the form base(...), that constructor implicitly performs the initializations specified by the variable_initializers of the instance fields declared in its class. Isso corresponde a uma sequência de atribuições que são executados imediatamente após a entrada para o construtor e antes da invocação do construtor de classe base direta implícita.This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor and before the implicit invocation of the direct base class constructor. Os inicializadores de variável são executados na ordem textual em que aparecem na declaração da classe.The variable initializers are executed in the textual order in which they appear in the class declaration.

Execução do construtorConstructor execution

Inicializadores de variável são transformados em instruções de atribuição, e essas instruções de atribuição são executadas antes da invocação do construtor de instância de classe base.Variable initializers are transformed into assignment statements, and these assignment statements are executed before the invocation of the base class instance constructor. Essa ordenação garantirá que todos os campos de instância são inicializados por seus inicializadores de variável antes de quaisquer declarações que têm acesso a essa instância são executadas.This ordering ensures that all instance fields are initialized by their variable initializers before any statements that have access to that instance are executed.

O exemploGiven the example

using System;

class A
{
    public A() {
        PrintFields();
    }

    public virtual void PrintFields() {}
}

class B: A
{
    int x = 1;
    int y;

    public B() {
        y = -1;
    }

    public override void PrintFields() {
        Console.WriteLine("x = {0}, y = {1}", x, y);
    }
}

Quando new B() é usado para criar uma instância de B, a seguinte saída é produzida:when new B() is used to create an instance of B, the following output is produced:

x = 1, y = 0

O valor de x é 1, porque o inicializador de variável é executado antes que o construtor de instância de classe base seja invocado.The value of x is 1 because the variable initializer is executed before the base class instance constructor is invoked. No entanto, o valor de y é 0 (o valor padrão de um int) porque a atribuição ao y não é executada até depois que o construtor de classe base retorna.However, the value of y is 0 (the default value of an int) because the assignment to y is not executed until after the base class constructor returns.

É útil pensar em inicializadores de construtor e inicializadores de variável de instância como instruções que são automaticamente inseridas antes do constructor_body.It is useful to think of instance variable initializers and constructor initializers as statements that are automatically inserted before the constructor_body. O exemploThe example

using System;
using System.Collections;

class A
{
    int x = 1, y = -1, count;

    public A() {
        count = 0;
    }

    public A(int n) {
        count = n;
    }
}

class B: A
{
    double sqrt2 = Math.Sqrt(2.0);
    ArrayList items = new ArrayList(100);
    int max;

    public B(): this(100) {
        items.Add("default");
    }

    public B(int n): base(n - 1) {
        max = n;
    }
}

contém várias inicializadores de variável; Ele também contém os inicializadores de construtor de ambos os formulários (base e this).contains several variable initializers; it also contains constructor initializers of both forms (base and this). O exemplo corresponde ao código mostrado abaixo, onde cada comentário indica uma instrução inserida automaticamente (a sintaxe usada para as invocações de construtor automaticamente inserido não é válido, mas serve apenas para ilustrar o mecanismo).The example corresponds to the code shown below, where each comment indicates an automatically inserted statement (the syntax used for the automatically inserted constructor invocations isn't valid, but merely serves to illustrate the mechanism).

using System.Collections;

class A
{
    int x, y, count;

    public A() {
        x = 1;                       // Variable initializer
        y = -1;                      // Variable initializer
        object();                    // Invoke object() constructor
        count = 0;
    }

    public A(int n) {
        x = 1;                       // Variable initializer
        y = -1;                      // Variable initializer
        object();                    // Invoke object() constructor
        count = n;
    }
}

class B: A
{
    double sqrt2;
    ArrayList items;
    int max;

    public B(): this(100) {
        B(100);                      // Invoke B(int) constructor
        items.Add("default");
    }

    public B(int n): base(n - 1) {
        sqrt2 = Math.Sqrt(2.0);      // Variable initializer
        items = new ArrayList(100);  // Variable initializer
        A(n - 1);                    // Invoke A(int) constructor
        max = n;
    }
}

Construtores padrãoDefault constructors

Se uma classe não contiver nenhuma declaração de construtor de instância, um construtor de instância padrão é fornecido automaticamente.If a class contains no instance constructor declarations, a default instance constructor is automatically provided. Esse construtor padrão simplesmente invoca o construtor sem parâmetros da classe base direta.That default constructor simply invokes the parameterless constructor of the direct base class. Se a classe é abstrata a acessibilidade declarada para o construtor padrão é protegida.If the class is abstract then the declared accessibility for the default constructor is protected. Caso contrário, a acessibilidade declarada para o construtor padrão é pública.Otherwise, the declared accessibility for the default constructor is public. Portanto, o construtor padrão sempre é do formulárioThus, the default constructor is always of the form

protected C(): base() {}

ouor

public C(): base() {}

onde C é o nome da classe.where C is the name of the class. Se a resolução de sobrecarga não puder determinar um melhor candidato exclusivo para o inicializador do construtor de classe base ocorrerá um erro de tempo de compilação.If overload resolution is unable to determine a unique best candidate for the base class constructor initializer then a compile-time error occurs.

No exemploIn the example

class Message
{
    object sender;
    string text;
}

um construtor padrão é fornecido porque a classe não contém nenhuma declaração de construtor de instância.a default constructor is provided because the class contains no instance constructor declarations. Portanto, o exemplo é precisamente equivalente aThus, the example is precisely equivalent to

class Message
{
    object sender;
    string text;

    public Message(): base() {}
}

Construtores particularesPrivate constructors

Quando uma classe T declara apenas construtores de instância privada, não é possível para as classes fora do texto de programa do T derivar T ou para criar diretamente instâncias do T.When a class T declares only private instance constructors, it is not possible for classes outside the program text of T to derive from T or to directly create instances of T. Assim, se uma classe contém apenas membros estáticos e não se destina a ser instanciado, adicionar um construtor de instância privada vazio impedirá instanciação.Thus, if a class contains only static members and isn't intended to be instantiated, adding an empty private instance constructor will prevent instantiation. Por exemplo:For example:

public class Trig
{
    private Trig() {}        // Prevent instantiation

    public const double PI = 3.14159265358979323846;

    public static double Sin(double x) {...}
    public static double Cos(double x) {...}
    public static double Tan(double x) {...}
}

O Trig classe grupos constantes e métodos relacionados, mas não se destina a ser instanciado.The Trig class groups related methods and constants, but is not intended to be instantiated. Portanto, ele declara um construtor de instância única de privado vazio.Therefore it declares a single empty private instance constructor. Construtor de pelo menos uma instância deve ser declarado para suprimir a geração automática de um construtor padrão.At least one instance constructor must be declared to suppress the automatic generation of a default constructor.

Parâmetros do construtor de instância opcionalOptional instance constructor parameters

O this(...) formulário de inicializador de construtor é comumente usado em conjunto com sobrecarga para implementar os parâmetros do construtor de instância opcional.The this(...) form of constructor initializer is commonly used in conjunction with overloading to implement optional instance constructor parameters. No exemploIn the example

class Text
{
    public Text(): this(0, 0, null) {}

    public Text(int x, int y): this(x, y, null) {}

    public Text(int x, int y, string s) {
        // Actual constructor implementation
    }
}

os construtores de dois instância primeiro simplesmente fornecem os valores padrão para os argumentos ausentes.the first two instance constructors merely provide the default values for the missing arguments. Ambos usam um this(...) inicializador de construtor para invocar o terceiro construtor de instância, o que realmente faz o trabalho de inicializar a nova instância.Both use a this(...) constructor initializer to invoke the third instance constructor, which actually does the work of initializing the new instance. O efeito é que um dos parâmetros do construtor opcional:The effect is that of optional constructor parameters:

Text t1 = new Text();                    // Same as Text(0, 0, null)
Text t2 = new Text(5, 10);               // Same as Text(5, 10, null)
Text t3 = new Text(5, 20, "Hello");

Construtores estáticosStatic constructors

Um construtor estático é um membro que implementa as ações necessárias para inicializar um tipo de classe fechado.A static constructor is a member that implements the actions required to initialize a closed class type. Construtores estáticos são declarados usando static_constructor_declarations:Static constructors are declared using static_constructor_declarations:

static_constructor_declaration
    : attributes? static_constructor_modifiers identifier '(' ')' static_constructor_body
    ;

static_constructor_modifiers
    : 'extern'? 'static'
    | 'static' 'extern'?
    | static_constructor_modifiers_unsafe
    ;

static_constructor_body
    : block
    | ';'
    ;

Um static_constructor_declaration pode incluir um conjunto de atributos (atributos) e um extern modificador (métodos externos).A static_constructor_declaration may include a set of attributes (Attributes) and an extern modifier (External methods).

O identificador de uma static_constructor_declaration deve nomear a classe na qual o construtor estático é declarado.The identifier of a static_constructor_declaration must name the class in which the static constructor is declared. Se nenhum outro nome for especificado, ocorrerá um erro de tempo de compilação.If any other name is specified, a compile-time error occurs.

Quando uma declaração de construtor estático inclui um extern modificador, o construtor estático é considerado uma externo construtor estático.When a static constructor declaration includes an extern modifier, the static constructor is said to be an external static constructor. Como uma declaração de construtor estático externo não fornece nenhuma implementação real, sua static_constructor_body consiste em um ponto e vírgula.Because an external static constructor declaration provides no actual implementation, its static_constructor_body consists of a semicolon. Para todas as outras declarações de construtor estático, o static_constructor_body consiste em um bloco que especifica as instruções para executar a fim de inicializar a classe.For all other static constructor declarations, the static_constructor_body consists of a block which specifies the statements to execute in order to initialize the class. Isso corresponde exatamente a method_body de um método estático com um void tipo de retorno (corpo do método).This corresponds exactly to the method_body of a static method with a void return type (Method body).

Construtores estáticos não são herdados e não podem ser chamados diretamente.Static constructors are not inherited, and cannot be called directly.

O construtor estático para um tipo de classe fechado é executado no máximo uma vez em um determinado domínio de aplicativo.The static constructor for a closed class type executes at most once in a given application domain. A execução de um construtor estático é disparada pela primeira dos seguintes eventos ocorra dentro de um domínio de aplicativo:The execution of a static constructor is triggered by the first of the following events to occur within an application domain:

  • Uma instância do tipo de classe é criada.An instance of the class type is created.
  • Qualquer um dos membros estáticos do tipo de classe são referenciados.Any of the static members of the class type are referenced.

Se uma classe contém o Main método (inicialização do aplicativo) em que a execução começa, o construtor estático para essa classe é executado antes de Main método é chamado.If a class contains the Main method (Application Startup) in which execution begins, the static constructor for that class executes before the Main method is called.

Para inicializar um novo tipo de classes fechado, primeiro um novo conjunto de campos estáticos (campos estáticos e de instância) para esse tipo específico de fechado é criado.To initialize a new closed class type, first a new set of static fields (Static and instance fields) for that particular closed type is created. Cada um dos campos estáticos é inicializada com seu valor padrão (valores padrão).Each of the static fields is initialized to its default value (Default values). Em seguida, os inicializadores de campo estático (inicialização do campo estático) são executadas para esses campos estáticos.Next, the static field initializers (Static field initialization) are executed for those static fields. Por fim, o construtor estático é executado.Finally, the static constructor is executed.

O exemploThe example

using System;

class Test
{
    static void Main() {
        A.F();
        B.F();
    }
}

class A
{
    static A() {
        Console.WriteLine("Init A");
    }
    public static void F() {
        Console.WriteLine("A.F");
    }
}

class B
{
    static B() {
        Console.WriteLine("Init B");
    }
    public static void F() {
        Console.WriteLine("B.F");
    }
}

deve produzir a saída:must produce the output:

Init A
A.F
Init B
B.F

porque a execução de Ado construtor estático é disparado pela chamada para A.Fe a execução de Bdo construtor estático é disparado pela chamada para B.F.because the execution of A's static constructor is triggered by the call to A.F, and the execution of B's static constructor is triggered by the call to B.F.

É possível criar dependências circulares que permitem que os campos estáticos com inicializadores de variável a ser observado em seu estado de valor padrão.It is possible to construct circular dependencies that allow static fields with variable initializers to be observed in their default value state.

O exemploThe example

using System;

class A
{
    public static int X;

    static A() {
        X = B.Y + 1;
    }
}

class B
{
    public static int Y = A.X + 1;

    static B() {}

    static void Main() {
        Console.WriteLine("X = {0}, Y = {1}", A.X, B.Y);
    }
}

produz a saídaproduces the output

X = 1, Y = 2

Para executar o Main método, o sistema pela primeira vez é executado o inicializador para B.Y, antes de classe Bdo construtor estático.To execute the Main method, the system first runs the initializer for B.Y, prior to class B's static constructor. Ydo inicializador faz com que Ado construtor estático para ser executado porque o valor de A.X é referenciado.Y's initializer causes A's static constructor to be run because the value of A.X is referenced. O construtor estático de A por sua vez prossegue para calcular o valor da Xe fazer buscas caso o valor padrão de Y, que é zero.The static constructor of A in turn proceeds to compute the value of X, and in doing so fetches the default value of Y, which is zero. A.X Portanto, é inicializado como 1.A.X is thus initialized to 1. O processo de execução Ado construtor estático e inicializadores de campo estático, em seguida, for concluído, retornando para o cálculo do valor inicial do Y, cujo resultado se torna 2.The process of running A's static field initializers and static constructor then completes, returning to the calculation of the initial value of Y, the result of which becomes 2.

Como o construtor estático é executado exatamente uma vez para cada fechado o tipo de classe construída, é um local conveniente para impor verificações de tempo de execução no parâmetro de tipo não podem ser verificados em tempo de compilação por meio de restrições (parâmetro de tipo restrições de).Because the static constructor is executed exactly once for each closed constructed class type, it is a convenient place to enforce run-time checks on the type parameter that cannot be checked at compile-time via constraints (Type parameter constraints). Por exemplo, o tipo a seguir usa um construtor estático para impor que o argumento de tipo é um enum:For example, the following type uses a static constructor to enforce that the type argument is an enum:

class Gen<T> where T: struct
{
    static Gen() {
        if (!typeof(T).IsEnum) {
            throw new ArgumentException("T must be an enum");
        }
    }
}

DestruidoresDestructors

Um destruidor é um membro que implementa as ações necessárias para destruir uma instância de uma classe.A destructor is a member that implements the actions required to destruct an instance of a class. Um destruidor for declarado usando um destructor_declaration:A destructor is declared using a destructor_declaration:

destructor_declaration
    : attributes? 'extern'? '~' identifier '(' ')' destructor_body
    | destructor_declaration_unsafe
    ;

destructor_body
    : block
    | ';'
    ;

Um destructor_declaration pode incluir um conjunto de atributos (atributos).A destructor_declaration may include a set of attributes (Attributes).

O identificador de uma destructor_declaration deve nomear a classe em que o destruidor for declarado.The identifier of a destructor_declaration must name the class in which the destructor is declared. Se nenhum outro nome for especificado, ocorrerá um erro de tempo de compilação.If any other name is specified, a compile-time error occurs.

Quando uma declaração de destruidor inclui um extern modificador, o destruidor deve ser um destruidor externo.When a destructor declaration includes an extern modifier, the destructor is said to be an external destructor. Como uma declaração de destruidor externo não fornece nenhuma implementação real, sua destructor_body consiste em um ponto e vírgula.Because an external destructor declaration provides no actual implementation, its destructor_body consists of a semicolon. Para todos os destruidores, o destructor_body consiste em um bloco que especifica as instruções a executar para destruir uma instância da classe.For all other destructors, the destructor_body consists of a block which specifies the statements to execute in order to destruct an instance of the class. Um destructor_body corresponde exatamente a method_body de um método de instância com um void tipo de retorno (corpo do método).A destructor_body corresponds exactly to the method_body of an instance method with a void return type (Method body).

Destruidores não são herdados.Destructors are not inherited. Portanto, uma classe não possui nenhum destruidor diferente daquele que podem ser declarados nessa classe.Thus, a class has no destructors other than the one which may be declared in that class.

Uma vez que um destruidor deve não ter nenhum parâmetro, não pode ser sobrecarregado, portanto, uma classe pode ter, no máximo, um destruidor.Since a destructor is required to have no parameters, it cannot be overloaded, so a class can have, at most, one destructor.

Os destruidores são invocados automaticamente e não podem ser invocados explicitamente.Destructors are invoked automatically, and cannot be invoked explicitly. Uma instância não estiver qualificada para destruição quando ele não é mais possível para qualquer código usar essa instância.An instance becomes eligible for destruction when it is no longer possible for any code to use that instance. Execução do destruidor para a instância pode ocorrer a qualquer momento depois que a instância se tornar qualificada para destruição.Execution of the destructor for the instance may occur at any time after the instance becomes eligible for destruction. Quando uma instância é destruída, os destruidores na cadeia de herança da instância são chamados na ordem, do mais derivado para menos derivado.When an instance is destructed, the destructors in that instance's inheritance chain are called, in order, from most derived to least derived. Um destruidor pode ser executado em qualquer thread.A destructor may be executed on any thread. Para mais informações sobre as regras que determinam quando e como um destruidor é executado, consulte gerenciamento automático de memória.For further discussion of the rules that govern when and how a destructor is executed, see Automatic memory management.

A saída do exemploThe output of the example

using System;

class A
{
    ~A() {
        Console.WriteLine("A's destructor");
    }
}

class B: A
{
    ~B() {
        Console.WriteLine("B's destructor");
    }
}

class Test
{
   static void Main() {
        B b = new B();
        b = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
   }
}

isis

B's destructor
A's destructor

uma vez que os destruidores em uma cadeia de herança são chamados na ordem, do mais derivado para menos derivado.since destructors in an inheritance chain are called in order, from most derived to least derived.

Os destruidores são implementados, substituindo o método virtual Finalize em System.Object.Destructors are implemented by overriding the virtual method Finalize on System.Object. Programas em c# não tem permissão para substituir este método ou ligue para (ou substituições dele) diretamente.C# programs are not permitted to override this method or call it (or overrides of it) directly. Por exemplo, o programaFor instance, the program

class A 
{
    override protected void Finalize() {}    // error

    public void F() {
        this.Finalize();                     // error
    }
}

contém dois erros.contains two errors.

O compilador se comporta como se esse método e substituições do mesmo, não existem em todos os.The compiler behaves as if this method, and overrides of it, do not exist at all. Portanto, este programa:Thus, this program:

class A 
{
    void Finalize() {}                            // permitted
}

é válido, e o método mostrado oculta System.Objectdo Finalize método.is valid, and the method shown hides System.Object's Finalize method.

Para obter uma discussão sobre o comportamento quando uma exceção for lançada de um destruidor, consulte como exceções são tratadas.For a discussion of the behavior when an exception is thrown from a destructor, see How exceptions are handled.

IteratorsIterators

Um membro da função (membros de função) implementado usando um bloco de iteradores (blocos) é chamado um iterador.A function member (Function members) implemented using an iterator block (Blocks) is called an iterator.

Um bloco de iteradores pode ser usado como o corpo de um membro da função, desde que o tipo de retorno do membro da função correspondente é uma das interfaces de enumerador (interfaces de enumerador) ou uma das interfaces enumeráveis (Interfaces enumeráveis).An iterator block may be used as the body of a function member as long as the return type of the corresponding function member is one of the enumerator interfaces (Enumerator interfaces) or one of the enumerable interfaces (Enumerable interfaces). Ele pode ocorrer como um method_body, operator_body ou accessor_body, enquanto eventos, construtores de instância, estáticas construtores e destruidores não podem ser implementadas como iteradores.It can occur as a method_body, operator_body or accessor_body, whereas events, instance constructors, static constructors and destructors cannot be implemented as iterators.

Quando um membro da função é implementado usando um bloco de iteradores, ele é um erro de tempo de compilação para a lista de parâmetros formais do membro da função para especificar qualquer ref ou out parâmetros.When a function member is implemented using an iterator block, it is a compile-time error for the formal parameter list of the function member to specify any ref or out parameters.

Interfaces de enumeradorEnumerator interfaces

O interfaces de enumerador são a interface não genérica System.Collections.IEnumerator e em todas as instanciações da interface genérica System.Collections.Generic.IEnumerator<T>.The enumerator interfaces are the non-generic interface System.Collections.IEnumerator and all instantiations of the generic interface System.Collections.Generic.IEnumerator<T>. Por questão de brevidade, neste capítulo essas interfaces são referenciadas como IEnumerator e IEnumerator<T>, respectivamente.For the sake of brevity, in this chapter these interfaces are referenced as IEnumerator and IEnumerator<T>, respectively.

Interfaces enumeráveisEnumerable interfaces

O interfaces enumeráveis são a interface não genérica System.Collections.IEnumerable e em todas as instanciações da interface genérica System.Collections.Generic.IEnumerable<T>.The enumerable interfaces are the non-generic interface System.Collections.IEnumerable and all instantiations of the generic interface System.Collections.Generic.IEnumerable<T>. Por questão de brevidade, neste capítulo essas interfaces são referenciadas como IEnumerable e IEnumerable<T>, respectivamente.For the sake of brevity, in this chapter these interfaces are referenced as IEnumerable and IEnumerable<T>, respectively.

Tipo de rendimentoYield type

Um iterador produz uma sequência de valores, todos do mesmo tipo.An iterator produces a sequence of values, all of the same type. Esse tipo é chamado de yield tipo do iterador.This type is called the yield type of the iterator.

  • O tipo de rendimento de um iterador que retorna IEnumerator ou IEnumerable é object.The yield type of an iterator that returns IEnumerator or IEnumerable is object.
  • O tipo de rendimento de um iterador que retorna IEnumerator<T> ou IEnumerable<T> é T.The yield type of an iterator that returns IEnumerator<T> or IEnumerable<T> is T.

Objetos de enumeradorEnumerator objects

Quando um membro da função retornando um enumerador de tipo de interface é implementado usando um bloco de iteradores, invocar o membro da função não é imediatamente executado o código no bloco de iterador.When a function member returning an enumerator interface type is implemented using an iterator block, invoking the function member does not immediately execute the code in the iterator block. Em vez disso, uma objeto enumerador é criada e retornada.Instead, an enumerator object is created and returned. Esse objeto encapsula o código especificado no bloco de iterador e a execução do código no bloco iterador ocorre quando o objeto de enumerador MoveNext método é invocado.This object encapsulates the code specified in the iterator block, and execution of the code in the iterator block occurs when the enumerator object's MoveNext method is invoked. Um objeto de enumerador tem as seguintes características:An enumerator object has the following characteristics:

  • Ele implementa IEnumerator e IEnumerator<T>, onde T é o tipo de yield do iterador.It implements IEnumerator and IEnumerator<T>, where T is the yield type of the iterator.
  • Ele implementa System.IDisposable.It implements System.IDisposable.
  • Ele é inicializado com uma cópia dos valores de argumento (se houver) e o valor da instância passada para o membro da função.It is initialized with a copy of the argument values (if any) and instance value passed to the function member.
  • Ele tem quatro estados possíveis, antes de, executando, suspenso, e depoise é inicialmente no antes estado.It has four potential states, before, running, suspended, and after, and is initially in the before state.

Um objeto de enumerador normalmente é uma instância de uma classe de enumerador gerado pelo compilador que encapsula o código no bloco de iterador e implementa as interfaces de enumerador, mas outros métodos de implementação são possíveis.An enumerator object is typically an instance of a compiler-generated enumerator class that encapsulates the code in the iterator block and implements the enumerator interfaces, but other methods of implementation are possible. Se uma classe de enumerador é gerada pelo compilador, essa classe será ser aninhada, direta ou indiretamente, na classe que contém o membro da função, ela tem acessibilidade privada e ele terá um nome reservado para uso pelo compilador (identificadores ).If an enumerator class is generated by the compiler, that class will be nested, directly or indirectly, in the class containing the function member, it will have private accessibility, and it will have a name reserved for compiler use (Identifiers).

Um objeto de enumerador pode implementar mais interfaces daqueles especificados acima.An enumerator object may implement more interfaces than those specified above.

As seções a seguir descrevem o comportamento exato do MoveNext, Current, e Dispose membros a IEnumerable e IEnumerable<T> fornecidas por um objeto de enumerador de implementações de interface.The following sections describe the exact behavior of the MoveNext, Current, and Dispose members of the IEnumerable and IEnumerable<T> interface implementations provided by an enumerator object.

Observe que não têm suporte para objetos de enumerador a IEnumerator.Reset método.Note that enumerator objects do not support the IEnumerator.Reset method. Invocar esse método faz com que um System.NotSupportedException seja lançada.Invoking this method causes a System.NotSupportedException to be thrown.

O método MoveNextThe MoveNext method

O MoveNext método de um objeto de enumerador encapsula o código de um bloco de iteradores.The MoveNext method of an enumerator object encapsulates the code of an iterator block. Invocar o MoveNext método executa o código no bloco de iteradores e conjuntos de Current propriedade do objeto enumerador conforme apropriado.Invoking the MoveNext method executes code in the iterator block and sets the Current property of the enumerator object as appropriate. Precisa ação executada pelo MoveNext depende do estado do objeto enumerador quando MoveNext é invocado:The precise action performed by MoveNext depends on the state of the enumerator object when MoveNext is invoked:

  • Se for o estado do objeto enumerador antes de, chamar MoveNext:If the state of the enumerator object is before, invoking MoveNext:
    • Altera o estado para executando.Changes the state to running.
    • Inicializa os parâmetros (incluindo this) do bloco de iterador com os valores de argumento e o valor de instância salvo quando o objeto de enumerador foi inicializado.Initializes the parameters (including this) of the iterator block to the argument values and instance value saved when the enumerator object was initialized.
    • Executa o bloco de iteradores desde o início até que a execução é interrompida (conforme descrito abaixo).Executes the iterator block from the beginning until execution is interrupted (as described below).
  • Se for o estado do objeto enumerador em execução, o resultado da invocação MoveNext não está especificado.If the state of the enumerator object is running, the result of invoking MoveNext is unspecified.
  • Se for o estado do objeto enumerador suspensos, chamar MoveNext:If the state of the enumerator object is suspended, invoking MoveNext:
    • Altera o estado para executando.Changes the state to running.
    • Restaura os valores de todas as variáveis locais e parâmetros (inclusive este) para os valores salvos quando a execução do bloco iterador foi suspenso pela última vez.Restores the values of all local variables and parameters (including this) to the values saved when execution of the iterator block was last suspended. Observe que o conteúdo de todos os objetos referenciados por essas variáveis pode ter mudado desde a chamada anterior a MoveNext.Note that the contents of any objects referenced by these variables may have changed since the previous call to MoveNext.
    • Retoma a execução do bloco de iterador imediatamente após o yield return instrução que causou a suspensão de execução e continua até que a execução é interrompida (conforme descrito abaixo).Resumes execution of the iterator block immediately following the yield return statement that caused the suspension of execution and continues until execution is interrupted (as described below).
  • Se for o estado do objeto enumerador após, chamar MoveNext retorna false.If the state of the enumerator object is after, invoking MoveNext returns false.

Quando MoveNext executa o bloco de iteradores, execução pode ser interrompida de quatro maneiras: Por um yield return instrução, por um yield break instrução, encontrando o final do bloco de iterador e por uma exceção sendo lançada e propagada para fora do bloco de iterador.When MoveNext executes the iterator block, execution can be interrupted in four ways: By a yield return statement, by a yield break statement, by encountering the end of the iterator block, and by an exception being thrown and propagated out of the iterator block.

  • Quando um yield return instrução for encontrada (a instrução yield):When a yield return statement is encountered (The yield statement):
    • A expressão fornecida na instrução é avaliada implicitamente convertida no tipo de rendimento e atribuída ao Current propriedade do objeto enumerador.The expression given in the statement is evaluated, implicitly converted to the yield type, and assigned to the Current property of the enumerator object.
    • Execução do corpo do iterador é suspenso.Execution of the iterator body is suspended. Os valores de todos os parâmetros e variáveis locais (incluindo this) são salvas, como é o local deste yield return instrução.The values of all local variables and parameters (including this) are saved, as is the location of this yield return statement. Se o yield return instrução está dentro de um ou mais try bloqueia associado finally blocos não são executados no momento.If the yield return statement is within one or more try blocks, the associated finally blocks are not executed at this time.
    • O estado do objeto enumerador é alterado para suspenso.The state of the enumerator object is changed to suspended.
    • O MoveNext retorno do método true para seu chamador, que indica que a iteração avançado com êxito para o próximo valor.The MoveNext method returns true to its caller, indicating that the iteration successfully advanced to the next value.
  • Quando um yield break instrução for encontrada (a instrução yield):When a yield break statement is encountered (The yield statement):
    • Se o yield break instrução está dentro de um ou mais try bloqueia associado finally blocos são executados.If the yield break statement is within one or more try blocks, the associated finally blocks are executed.
    • O estado do objeto enumerador é alterado para depois de.The state of the enumerator object is changed to after.
    • O MoveNext retorno do método false para seu chamador, que indica que a iteração foi concluída.The MoveNext method returns false to its caller, indicating that the iteration is complete.
  • Quando o final do corpo do iterador for encontrado:When the end of the iterator body is encountered:
    • O estado do objeto enumerador é alterado para depois de.The state of the enumerator object is changed to after.
    • O MoveNext retorno do método false para seu chamador, que indica que a iteração foi concluída.The MoveNext method returns false to its caller, indicating that the iteration is complete.
  • Quando uma exceção é lançada e propagada para fora do bloco de iterador:When an exception is thrown and propagated out of the iterator block:
    • Apropriado finally blocos no corpo do iterador serão foram executados pela propagação de exceção.Appropriate finally blocks in the iterator body will have been executed by the exception propagation.
    • O estado do objeto enumerador é alterado para depois de.The state of the enumerator object is changed to after.
    • A propagação de exceção continuará para o chamador do MoveNext método.The exception propagation continues to the caller of the MoveNext method.

A propriedade atualThe Current property

Um objeto de enumerador Current propriedade é afetada pela yield return instruções no bloco de iterador.An enumerator object's Current property is affected by yield return statements in the iterator block.

Quando um objeto de enumerador está no suspensos de estado, o valor de Current é o valor definido pela chamada anterior para MoveNext.When an enumerator object is in the suspended state, the value of Current is the value set by the previous call to MoveNext. Quando um objeto de enumerador está no antes de, executando, ou depois afirma, o resultado de acessar Current não está especificado.When an enumerator object is in the before, running, or after states, the result of accessing Current is unspecified.

Para um iterador com um rendimento tipo diferente de object, o resultado de acessando Current por meio do objeto de enumerador IEnumerable implementação corresponde ao acessar Current por meio do objeto de enumerador IEnumerator<T> implementação e convertendo o resultado para object.For an iterator with a yield type other than object, the result of accessing Current through the enumerator object's IEnumerable implementation corresponds to accessing Current through the enumerator object's IEnumerator<T> implementation and casting the result to object.

O método DisposeThe Dispose method

O Dispose método é usado para limpar a iteração, colocando o objeto enumerador o depois estado.The Dispose method is used to clean up the iteration by bringing the enumerator object to the after state.

  • Se for o estado do objeto enumerador antes de, chamar Dispose altera o estado para depois.If the state of the enumerator object is before, invoking Dispose changes the state to after.
  • Se for o estado do objeto enumerador em execução, o resultado da invocação Dispose não está especificado.If the state of the enumerator object is running, the result of invoking Dispose is unspecified.
  • Se for o estado do objeto enumerador suspensos, chamar Dispose:If the state of the enumerator object is suspended, invoking Dispose:
    • Altera o estado para executando.Changes the state to running.
    • Executa qualquer finalmente blocos como se o último executado yield return instrução foram um yield break instrução.Executes any finally blocks as if the last executed yield return statement were a yield break statement. Se isso faz com que uma exceção seja gerada e propagadas para fora do corpo do iterador, o estado do objeto enumerador é definido como após e a exceção é propagada para o chamador do Dispose método.If this causes an exception to be thrown and propagated out of the iterator body, the state of the enumerator object is set to after and the exception is propagated to the caller of the Dispose method.
    • Altera o estado para depois de.Changes the state to after.
  • Se for o estado do objeto enumerador após, chamar Dispose não tem nenhum efeito.If the state of the enumerator object is after, invoking Dispose has no affect.

Objetos enumeráveisEnumerable objects

Quando um membro da função retornando um tipo enumerável interface é implementado usando um bloco de iteradores, invocar o membro da função não é imediatamente executado o código no bloco de iterador.When a function member returning an enumerable interface type is implemented using an iterator block, invoking the function member does not immediately execute the code in the iterator block. Em vez disso, uma objeto enumerável é criada e retornada.Instead, an enumerable object is created and returned. O objeto enumerável GetEnumerator método retorna um objeto enumerador que encapsula o código especificado no bloco de iterador e a execução do código no bloco iterador ocorre quando o objeto de enumerador MoveNext método é invocado.The enumerable object's GetEnumerator method returns an enumerator object that encapsulates the code specified in the iterator block, and execution of the code in the iterator block occurs when the enumerator object's MoveNext method is invoked. Um objeto enumerável tem as seguintes características:An enumerable object has the following characteristics:

  • Ele implementa IEnumerable e IEnumerable<T>, onde T é o tipo de yield do iterador.It implements IEnumerable and IEnumerable<T>, where T is the yield type of the iterator.
  • Ele é inicializado com uma cópia dos valores de argumento (se houver) e o valor da instância passada para o membro da função.It is initialized with a copy of the argument values (if any) and instance value passed to the function member.

Um objeto enumerável normalmente é uma instância de uma classe enumerable gerado pelo compilador que encapsula o código no bloco de iterador e implementa as interfaces enumeráveis, mas outros métodos de implementação são possíveis.An enumerable object is typically an instance of a compiler-generated enumerable class that encapsulates the code in the iterator block and implements the enumerable interfaces, but other methods of implementation are possible. Se uma classe enumerable é gerada pelo compilador, essa classe será ser aninhada, direta ou indiretamente, na classe que contém o membro da função, ela tem acessibilidade privada e ele terá um nome reservado para uso pelo compilador (identificadores ).If an enumerable class is generated by the compiler, that class will be nested, directly or indirectly, in the class containing the function member, it will have private accessibility, and it will have a name reserved for compiler use (Identifiers).

Um objeto enumerável pode implementar mais interfaces daqueles especificados acima.An enumerable object may implement more interfaces than those specified above. Em particular, também pode implementar um objeto enumerável IEnumerator e IEnumerator<T>, habilitá-la para servir como um enumerável e um enumerador.In particular, an enumerable object may also implement IEnumerator and IEnumerator<T>, enabling it to serve as both an enumerable and an enumerator. Esse tipo de implementação, a primeira vez que um objeto enumerável GetEnumerator método é invocado, o objeto enumerável em si é retornado.In that type of implementation, the first time an enumerable object's GetEnumerator method is invoked, the enumerable object itself is returned. As invocações subsequentes do objeto enumerável GetEnumerator, se houver, retornar uma cópia do objeto enumerável.Subsequent invocations of the enumerable object's GetEnumerator, if any, return a copy of the enumerable object. Assim, cada retornada enumerador tem seu próprio estado e as alterações em um enumerador não afetará outro.Thus, each returned enumerator has its own state and changes in one enumerator will not affect another.

O método GetEnumeratorThe GetEnumerator method

Um objeto enumerável fornece uma implementação do GetEnumerator métodos do IEnumerable e IEnumerable<T> interfaces.An enumerable object provides an implementation of the GetEnumerator methods of the IEnumerable and IEnumerable<T> interfaces. Os dois GetEnumerator métodos compartilham uma implementação comum que adquire e retorna um objeto de enumerador disponíveis.The two GetEnumerator methods share a common implementation that acquires and returns an available enumerator object. O objeto de enumerador é inicializada com os valores de argumento e a instância valor salvo quando o objeto enumerável foi inicializado, mas caso contrário, as funções de objeto de enumerador conforme descrito em objetos do enumerador.The enumerator object is initialized with the argument values and instance value saved when the enumerable object was initialized, but otherwise the enumerator object functions as described in Enumerator objects.

Exemplo de implementaçãoImplementation example

Esta seção descreve uma possível implementação de iteradores em termos de construções c# padrão.This section describes a possible implementation of iterators in terms of standard C# constructs. A implementação descrita aqui baseia-se os mesmos princípios usados pelo compilador Microsoft c#, mas ele não é uma implementação de conformidade ou o único possível.The implementation described here is based on the same principles used by the Microsoft C# compiler, but it is by no means a mandated implementation or the only one possible.

O seguinte Stack<T> classe implementa seu GetEnumerator método usando um iterador.The following Stack<T> class implements its GetEnumerator method using an iterator. O iterador enumera os elementos da pilha na parte superior para a parte inferior.The iterator enumerates the elements of the stack in top to bottom order.

using System;
using System.Collections;
using System.Collections.Generic;

class Stack<T>: IEnumerable<T>
{
    T[] items;
    int count;

    public void Push(T item) {
        if (items == null) {
            items = new T[4];
        }
        else if (items.Length == count) {
            T[] newItems = new T[count * 2];
            Array.Copy(items, 0, newItems, 0, count);
            items = newItems;
        }
        items[count++] = item;
    }

    public T Pop() {
        T result = items[--count];
        items[count] = default(T);
        return result;
    }

    public IEnumerator<T> GetEnumerator() {
        for (int i = count - 1; i >= 0; --i) yield return items[i];
    }
}

O GetEnumerator método pode ser convertido em uma instanciação de uma classe de enumerador gerado pelo compilador que encapsula o código no bloco de iterador, conforme mostrado a seguir.The GetEnumerator method can be translated into an instantiation of a compiler-generated enumerator class that encapsulates the code in the iterator block, as shown in the following.

class Stack<T>: IEnumerable<T>
{
    ...

    public IEnumerator<T> GetEnumerator() {
        return new __Enumerator1(this);
    }

    class __Enumerator1: IEnumerator<T>, IEnumerator
    {
        int __state;
        T __current;
        Stack<T> __this;
        int i;

        public __Enumerator1(Stack<T> __this) {
            this.__this = __this;
        }

        public T Current {
            get { return __current; }
        }

        object IEnumerator.Current {
            get { return __current; }
        }

        public bool MoveNext() {
            switch (__state) {
                case 1: goto __state1;
                case 2: goto __state2;
            }
            i = __this.count - 1;
        __loop:
            if (i < 0) goto __state2;
            __current = __this.items[i];
            __state = 1;
            return true;
        __state1:
            --i;
            goto __loop;
        __state2:
            __state = 2;
            return false;
        }

        public void Dispose() {
            __state = 2;
        }

        void IEnumerator.Reset() {
            throw new NotSupportedException();
        }
    }
}

A conversão anterior, o código no bloco iterador é transformado em uma máquina de estado e colocado no MoveNext método da classe de enumerador.In the preceding translation, the code in the iterator block is turned into a state machine and placed in the MoveNext method of the enumerator class. Além disso, a variável local i será transformado em um campo no objeto de enumerador para que ele possa continuar existindo entre invocações de MoveNext.Furthermore, the local variable i is turned into a field in the enumerator object so it can continue to exist across invocations of MoveNext.

O exemplo a seguir imprime uma simple tabela de multiplicação de números inteiros de 1 a 10.The following example prints a simple multiplication table of the integers 1 through 10. O FromTo método no exemplo retorna um objeto enumerável e é implementado usando um iterador.The FromTo method in the example returns an enumerable object and is implemented using an iterator.

using System;
using System.Collections.Generic;

class Test
{
    static IEnumerable<int> FromTo(int from, int to) {
        while (from <= to) yield return from++;
    }

    static void Main() {
        IEnumerable<int> e = FromTo(1, 10);
        foreach (int x in e) {
            foreach (int y in e) {
                Console.Write("{0,3} ", x * y);
            }
            Console.WriteLine();
        }
    }
}

O FromTo método pode ser convertido em uma instanciação de uma classe enumerable gerado pelo compilador que encapsula o código no bloco de iterador, conforme mostrado a seguir.The FromTo method can be translated into an instantiation of a compiler-generated enumerable class that encapsulates the code in the iterator block, as shown in the following.

using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;

class Test
{
    ...

    static IEnumerable<int> FromTo(int from, int to) {
        return new __Enumerable1(from, to);
    }

    class __Enumerable1:
        IEnumerable<int>, IEnumerable,
        IEnumerator<int>, IEnumerator
    {
        int __state;
        int __current;
        int __from;
        int from;
        int to;
        int i;

        public __Enumerable1(int __from, int to) {
            this.__from = __from;
            this.to = to;
        }

        public IEnumerator<int> GetEnumerator() {
            __Enumerable1 result = this;
            if (Interlocked.CompareExchange(ref __state, 1, 0) != 0) {
                result = new __Enumerable1(__from, to);
                result.__state = 1;
            }
            result.from = result.__from;
            return result;
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return (IEnumerator)GetEnumerator();
        }

        public int Current {
            get { return __current; }
        }

        object IEnumerator.Current {
            get { return __current; }
        }

        public bool MoveNext() {
            switch (__state) {
            case 1:
                if (from > to) goto case 2;
                __current = from++;
                __state = 1;
                return true;
            case 2:
                __state = 2;
                return false;
            default:
                throw new InvalidOperationException();
            }
        }

        public void Dispose() {
            __state = 2;
        }

        void IEnumerator.Reset() {
            throw new NotSupportedException();
        }
    }
}

A classe enumerable implementa as interfaces enumeráveis e as interfaces de enumerador, habilitá-la para servir como um enumerável e um enumerador.The enumerable class implements both the enumerable interfaces and the enumerator interfaces, enabling it to serve as both an enumerable and an enumerator. Na primeira vez o GetEnumerator método é invocado, o objeto enumerável em si é retornado.The first time the GetEnumerator method is invoked, the enumerable object itself is returned. As invocações subsequentes do objeto enumerável GetEnumerator, se houver, retornar uma cópia do objeto enumerável.Subsequent invocations of the enumerable object's GetEnumerator, if any, return a copy of the enumerable object. Assim, cada retornada enumerador tem seu próprio estado e as alterações em um enumerador não afetará outro.Thus, each returned enumerator has its own state and changes in one enumerator will not affect another. O Interlocked.CompareExchange método é usado para garantir a operação de thread-safe.The Interlocked.CompareExchange method is used to ensure thread-safe operation.

O from e to parâmetros são transformados em campos na classe enumerable.The from and to parameters are turned into fields in the enumerable class. Porque from é modificada no bloco de iterador, adicional __from campo é introduzido para conter o valor inicial fornecido para from em cada enumerador.Because from is modified in the iterator block, an additional __from field is introduced to hold the initial value given to from in each enumerator.

O MoveNext método lança um InvalidOperationException se ele é chamado quando __state é 0.The MoveNext method throws an InvalidOperationException if it is called when __state is 0. Isso protege contra o uso do objeto enumerável como um objeto de enumerador sem primeiro chamar GetEnumerator.This protects against use of the enumerable object as an enumerator object without first calling GetEnumerator.

O exemplo a seguir mostra uma classe simples de árvore.The following example shows a simple tree class. O Tree<T> classe implementa seu GetEnumerator método usando um iterador.The Tree<T> class implements its GetEnumerator method using an iterator. O iterador enumera os elementos da árvore em ordem de infixo.The iterator enumerates the elements of the tree in infix order.

using System;
using System.Collections.Generic;

class Tree<T>: IEnumerable<T>
{
    T value;
    Tree<T> left;
    Tree<T> right;

    public Tree(T value, Tree<T> left, Tree<T> right) {
        this.value = value;
        this.left = left;
        this.right = right;
    }

    public IEnumerator<T> GetEnumerator() {
        if (left != null) foreach (T x in left) yield x;
        yield value;
        if (right != null) foreach (T x in right) yield x;
    }
}

class Program
{
    static Tree<T> MakeTree<T>(T[] items, int left, int right) {
        if (left > right) return null;
        int i = (left + right) / 2;
        return new Tree<T>(items[i], 
            MakeTree(items, left, i - 1),
            MakeTree(items, i + 1, right));
    }

    static Tree<T> MakeTree<T>(params T[] items) {
        return MakeTree(items, 0, items.Length - 1);
    }

    // The output of the program is:
    // 1 2 3 4 5 6 7 8 9
    // Mon Tue Wed Thu Fri Sat Sun

    static void Main() {
        Tree<int> ints = MakeTree(1, 2, 3, 4, 5, 6, 7, 8, 9);
        foreach (int i in ints) Console.Write("{0} ", i);
        Console.WriteLine();

        Tree<string> strings = MakeTree(
            "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun");
        foreach (string s in strings) Console.Write("{0} ", s);
        Console.WriteLine();
    }
}

O GetEnumerator método pode ser convertido em uma instanciação de uma classe de enumerador gerado pelo compilador que encapsula o código no bloco de iterador, conforme mostrado a seguir.The GetEnumerator method can be translated into an instantiation of a compiler-generated enumerator class that encapsulates the code in the iterator block, as shown in the following.

class Tree<T>: IEnumerable<T>
{
    ...

    public IEnumerator<T> GetEnumerator() {
        return new __Enumerator1(this);
    }

    class __Enumerator1 : IEnumerator<T>, IEnumerator
    {
        Node<T> __this;
        IEnumerator<T> __left, __right;
        int __state;
        T __current;

        public __Enumerator1(Node<T> __this) {
            this.__this = __this;
        }

        public T Current {
            get { return __current; }
        }

        object IEnumerator.Current {
            get { return __current; }
        }

        public bool MoveNext() {
            try {
                switch (__state) {

                case 0:
                    __state = -1;
                    if (__this.left == null) goto __yield_value;
                    __left = __this.left.GetEnumerator();
                    goto case 1;

                case 1:
                    __state = -2;
                    if (!__left.MoveNext()) goto __left_dispose;
                    __current = __left.Current;
                    __state = 1;
                    return true;

                __left_dispose:
                    __state = -1;
                    __left.Dispose();

                __yield_value:
                    __current = __this.value;
                    __state = 2;
                    return true;

                case 2:
                    __state = -1;
                    if (__this.right == null) goto __end;
                    __right = __this.right.GetEnumerator();
                    goto case 3;

                case 3:
                    __state = -3;
                    if (!__right.MoveNext()) goto __right_dispose;
                    __current = __right.Current;
                    __state = 3;
                    return true;

                __right_dispose:
                    __state = -1;
                    __right.Dispose();

                __end:
                    __state = 4;
                    break;

                }
            }
            finally {
                if (__state < 0) Dispose();
            }
            return false;
        }

        public void Dispose() {
            try {
                switch (__state) {

                case 1:
                case -2:
                    __left.Dispose();
                    break;

                case 3:
                case -3:
                    __right.Dispose();
                    break;

                }
            }
            finally {
                __state = 4;
            }
        }

        void IEnumerator.Reset() {
            throw new NotSupportedException();
        }
    }
}

Os de temporários gerados pelo compilador usados na foreach instruções são elevadas para o __left e __right campos do objeto enumerador.The compiler generated temporaries used in the foreach statements are lifted into the __left and __right fields of the enumerator object. O __state campo do objeto enumerador é atualizado com cuidado para que o correto Dispose() método será chamado corretamente se uma exceção é lançada.The __state field of the enumerator object is carefully updated so that the correct Dispose() method will be called correctly if an exception is thrown. Observe que não é possível escrever o código traduzido com simples foreach instruções.Note that it is not possible to write the translated code with simple foreach statements.

Funções assíncronasAsync functions

Um método (métodos) ou função anônima (expressões de função anônima) com o async modificador é chamado um função assíncrona.A method (Methods) or anonymous function (Anonymous function expressions) with the async modifier is called an async function. Em geral, o termo async é usado para descrever qualquer tipo de função que tem o async modificador.In general, the term async is used to describe any kind of function that has the async modifier.

É um erro de tempo de compilação para a lista de parâmetros formais de uma função assíncrona para especificar qualquer ref ou out parâmetros.It is a compile-time error for the formal parameter list of an async function to specify any ref or out parameters.

O return_type de async método deve ser void ou uma tipo de tarefa.The return_type of an async method must be either void or a task type. Os tipos de tarefa são System.Threading.Tasks.Task e tipos construídos de System.Threading.Tasks.Task<T>.The task types are System.Threading.Tasks.Task and types constructed from System.Threading.Tasks.Task<T>. Por questão de brevidade, neste capítulo esses tipos são referenciados como Task e Task<T>, respectivamente.For the sake of brevity, in this chapter these types are referenced as Task and Task<T>, respectively. Um método assíncrono retorna um tipo de tarefa deve ser o retorno de tarefa.An async method returning a task type is said to be task-returning.

A definição exata dos tipos de tarefa é definido pela implementação, mas do ponto de vista da linguagem um tipo de tarefa está em um dos Estados incompletos, teve êxito ou falha.The exact definition of the task types is implementation defined, but from the language's point of view a task type is in one of the states incomplete, succeeded or faulted. Uma tarefa com falha registra uma exceção pertinente.A faulted task records a pertinent exception. Uma bem-sucedida Task<T> registra um resultado do tipo T.A succeeded Task<T> records a result of type T. Tipos de tarefa são aguardável e, portanto, podem ser os operandos de expressões await (expressões Await).Task types are awaitable, and can therefore be the operands of await expressions (Await expressions).

Uma invocação de função async tem a capacidade de suspender a avaliação por meio de expressões await (expressões Await) em seu corpo.An async function invocation has the ability to suspend evaluation by means of await expressions (Await expressions) in its body. Avaliação pode ser retomada posteriormente no ponto de suspensão await expressão por meio de um delegado de continuação.Evaluation may later be resumed at the point of the suspending await expression by means of a resumption delegate. O delegado de continuação é do tipo System.Action, e quando ele é chamado, a avaliação da invocação de função async será retomada da expressão await onde parou.The resumption delegate is of type System.Action, and when it is invoked, evaluation of the async function invocation will resume from the await expression where it left off. O chamador atual de uma função assíncrona invocação é o chamador original, se a invocação da função nunca foi suspenso ou o chamador mais recente do delegado de continuação caso contrário.The current caller of an async function invocation is the original caller if the function invocation has never been suspended, or the most recent caller of the resumption delegate otherwise.

Avaliação de uma função de retorno de tarefa de asyncEvaluation of a task-returning async function

Invocação de uma função de retorno de tarefa de async faz com que uma instância do tipo de tarefa retornada seja gerado.Invocation of a task-returning async function causes an instance of the returned task type to be generated. Isso é chamado de retornar task da função async.This is called the return task of the async function. A tarefa é inicialmente em um estado incompleto.The task is initially in an incomplete state.

O corpo da função de async é avaliado até que ele seja suspenso (por atingir uma expressão await) ou for encerrado, no qual o ponto de controle é retornado ao chamador, junto com a tarefa de retorno.The async function body is then evaluated until it is either suspended (by reaching an await expression) or terminates, at which point control is returned to the caller, along with the return task.

Quando o corpo da função async é encerrado, a tarefa de retornada é movida para fora do estado incompleto:When the body of the async function terminates, the return task is moved out of the incomplete state:

  • Se o corpo da função for encerrado como resultado de se atingir uma instrução return ou ao final do corpo, qualquer valor de resultado é registrada no task de retorno, que é colocado em um estado de êxito.If the function body terminates as the result of reaching a return statement or the end of the body, any result value is recorded in the return task, which is put into a succeeded state.
  • Se o corpo da função será encerrado devido a uma exceção não tratada (a instrução throw) a exceção é registrada no task de retorno que é colocado em um estado de falha.If the function body terminates as the result of an uncaught exception (The throw statement) the exception is recorded in the return task which is put into a faulted state.

Avaliação de uma função de async que retornam voidEvaluation of a void-returning async function

Se o tipo de retorno da função async é void, avaliação difere acima da seguinte maneira: Porque nenhuma tarefa é retornada, a função se comunica em vez disso, conclusão e exceções para o thread atual contexto de sincronização.If the return type of the async function is void, evaluation differs from the above in the following way: Because no task is returned, the function instead communicates completion and exceptions to the current thread's synchronization context. A definição exata de contexto de sincronização é dependente da implementação, mas é uma representação de "onde" o thread atual está em execução.The exact definition of synchronization context is implementation-dependent, but is a representation of "where" the current thread is running. O contexto de sincronização é notificado quando a avaliação de uma função de async que retornam void começa, for concluída com êxito ou faz com que uma exceção não percebida seja lançada.The synchronization context is notified when evaluation of a void-returning async function commences, completes successfully, or causes an uncaught exception to be thrown.

Isso permite que o contexto para controlar a execução de funções de async que retornam void quantos sob ele e decidir como propagar exceções provenientes proveito delas.This allows the context to keep track of how many void-returning async functions are running under it, and to decide how to propagate exceptions coming out of them.