Blocos de construção de programasProgram building blocks

Os tipos descritos no artigo anterior são criados usando estes blocos de construção: Membros, expressõese instruções.The types described in the previous article are built using these building blocks: members, expressions, and statements.

MembrosMembers

Os membros de a class são membros estáticos ou membros de instância.The members of a class are either static members or instance members. Os membros estáticos pertencem às classes e os membros de instância pertencem aos objetos (instâncias de classes).Static members belong to classes, and instance members belong to objects (instances of classes).

A lista a seguir fornece uma visão geral dos tipos de membros que uma classe pode conter.The following list provides an overview of the kinds of members a class can contain.

  • Constantes: valores constantes associados à classeConstants: Constant values associated with the class
  • Campos: variáveis que estão associadas à classeFields: Variables that are associated of the class
  • Métodos: ações que podem ser executadas pela classeMethods: Actions that can be performed by the class
  • Propriedades: ações associadas à leitura e à gravação de propriedades nomeadas da classeProperties: Actions associated with reading and writing named properties of the class
  • Indexadores: ações associadas à indexação de instâncias da classe como uma matrizIndexers: Actions associated with indexing instances of the class like an array
  • Eventos: notificações que podem ser geradas pela classeEvents: Notifications that can be generated by the class
  • Operadores: conversões e operadores de expressão com suporte na classeOperators: Conversions and expression operators supported by the class
  • Construtores: ações necessárias para inicializar instâncias da classe ou a própria classeConstructors: Actions required to initialize instances of the class or the class itself
  • Finalizadores: ações executadas antes de instâncias da classe serem descartadas permanentementeFinalizers: Actions performed before instances of the class are permanently discarded
  • Tipos: tipos aninhados declarados pela classeTypes: Nested types declared by the class

AcessibilidadeAccessibility

Cada membro de uma classe tem uma acessibilidade associada, que controla as regiões do texto do programa que podem acessar o membro.Each member of a class has an associated accessibility, which controls the regions of program text that can access the member. Existem seis formas possíveis de acessibilidade.There are six possible forms of accessibility. Os modificadores de acesso são resumidos abaixo.The access modifiers are summarized below.

  • public: O acesso não é limitado.public: Access isn't limited.
  • private: O acesso é limitado a essa classe.private: Access is limited to this class.
  • protected: O acesso é limitado a esta classe ou classes derivadas desta classe.protected: Access is limited to this class or classes derived from this class.
  • internal: O acesso é limitado ao assembly atual ( .exe ou .dll ).internal: Access is limited to the current assembly (.exe or .dll).
  • protected internal: O acesso é limitado a essa classe, classes derivadas dessa classe ou classes dentro do mesmo assembly.protected internal: Access is limited to this class, classes derived from this class, or classes within the same assembly.
  • private protected: O acesso é limitado a essa classe ou classes derivadas desse tipo dentro do mesmo assembly.private protected: Access is limited to this class or classes derived from this type within the same assembly.

CamposFields

Um campo é uma variável que está associada a uma classe ou a uma instância de uma classe.A field is a variable that is associated with a class or with an instance of a class.

Um campo declarado com o modificador estático define um campo estático.A field declared with the static modifier defines a static field. Um campo estático identifica exatamente um local de armazenamento.A static field identifies exactly one storage location. Não importa quantas instâncias de uma classe são criadas, há apenas uma cópia de um campo estático.No matter how many instances of a class are created, there's only ever one copy of a static field.

Um campo declarado sem o modificador estático define um campo de instância.A field declared without the static modifier defines an instance field. Cada instância de uma classe contém uma cópia separada de todos os campos de instância dessa classe.Every instance of a class contains a separate copy of all the instance fields of that class.

No exemplo a seguir, cada instância da Color classe tem uma cópia separada dos campos de r instância,, g e b , mas há apenas uma cópia dos Black White Red Green campos estáticos,,, e Blue :In the following example, each instance of the Color class has a separate copy of the r, g, and b instance fields, but there's only one copy of the Black, White, Red, Green, and Blue static fields:

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);
    
    public byte R { get; }
    public byte G { get; }
    public byte B { get; }

    public Color(byte r, byte g, byte b)
    {
        R = r;
        G = g;
        B = b;
    }
}

Conforme mostrado no exemplo anterior, os campos somente leitura podem ser declarados com um modificador readonly.As shown in the previous example, read-only fields may be declared with a readonly modifier. A atribuição a um campo somente leitura só pode ocorrer como parte da declaração do campo ou em um construtor na mesma classe.Assignment to a read-only field can only occur as part of the field’s declaration or in a constructor in the same class.

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 estáticos são acessados pela classe.Static methods are accessed through the class. Os métodos de instância são acessados pelas instâncias da classe.Instance methods are accessed through instances of the class.

Os métodos podem ter uma lista de parâmetros, que representam valores ou referências de variáveis passadas para o método.Methods may have a list of parameters, which represent values or variable references passed to the method. Os métodos têm um tipo de retorno, que especifica o tipo do valor calculado e retornado pelo método.Methods have a return type, which specifies the type of the value computed and returned by the method. O tipo de retorno de um método é void se ele não retornar um valor.A method’s return type is void if it doesn't return a value.

Como os tipos, os métodos também podem ter um conjunto de parâmetros de tipo, para que os quais os argumentos de tipo devem ser especificados quando o método é chamado.Like types, methods may also have a set of type parameters, for which type arguments must be specified when the method is called. Ao contrário dos tipos, os argumentos de tipo geralmente podem ser inferidos de argumentos de uma chamada de método e não precisam ser fornecidos explicitamente.Unlike types, the type arguments can often be inferred from the arguments of a method call and need not be explicitly given.

A assinatura de um método deve ser exclusiva na classe na qual o método é declarado.The signature of a method must be unique in the class in which the method is declared. A assinatura de um método consiste no nome do método, no número de parâmetros de tipo e no número, nos modificadores e nos tipos de seus parâmetros.The signature of a method consists of the name of the method, the number of type parameters, and the number, modifiers, and types of its parameters. A assinatura de um método não inclui o tipo de retorno.The signature of a method doesn't include the return type.

Quando um corpo de método é uma única expressão, o método pode ser definido usando um formato de expressão Compact, conforme mostrado no exemplo a seguir:When a method body is a single expression, the method can be defined using a compact expression format, as shown in the following example:

public override ToString() => "This is an object";

ParâmetrosParameters

Os parâmetros são usados para passar valores ou referências de variável aos métodos.Parameters are used to pass values or variable references to methods. Os parâmetros de um método obtêm seus valores reais de argumentos que são especificados quando o método é invocado.The parameters of a method get their actual values from the arguments that are specified when the method is invoked. Há quatro tipos de parâmetros: parâmetros de valor, parâmetros de referência, parâmetros de saída e matrizes de parâmetros.There are four kinds of parameters: value parameters, reference parameters, output parameters, and parameter arrays.

Um parâmetro de valor é usado para passar argumentos de entrada.A value parameter is used for passing input arguments. Um parâmetro de valor corresponde a uma variável local que obtém seu valor inicial do argumento passado para o parâmetro.A value parameter corresponds to a local variable that gets its initial value from the argument that was passed for the parameter. Modificações em um parâmetro de valor não afetam o argumento que foi passado para o parâmetro.Modifications to a value parameter don't affect the argument that was passed for the parameter.

Os parâmetros de valor podem ser opcionais, especificando um valor padrão para que os argumentos correspondentes possam ser omitidos.Value parameters can be optional, by specifying a default value so that corresponding arguments can be omitted.

Um parâmetro de referência é usado para passar argumentos por referência.A reference parameter is used for passing arguments by reference. O argumento passado para um parâmetro de referência deve ser uma variável com um valor definido.The argument passed for a reference parameter must be a variable with a definite value. Durante a execução do método, o parâmetro de referência representa o mesmo local de armazenamento que a variável de argumento.During execution of the method, the reference parameter represents the same storage location as the argument variable. Um parâmetro de referência é declarado com o modificador ref.A reference parameter is declared with the ref modifier. O exemplo a seguir mostra o uso de parâmetros ref.The following example shows the use of ref parameters.

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

public static void SwapExample()
{
    int i = 1, j = 2;
    Swap(ref i, ref j);
    Console.WriteLine($"{i} {j}");    // "2 1"
}

Um parâmetro de saída é usado para passar argumentos por referência.An output parameter is used for passing arguments by reference. Ele é semelhante a um parâmetro de referência, exceto que ele não requer que você atribua explicitamente um valor ao argumento fornecido pelo chamador.It's similar to a reference parameter, except that it doesn't require that you explicitly assign a value to the caller-provided argument. Um parâmetro de saída é declarado com o modificador out.An output parameter is declared with the out modifier. O exemplo a seguir mostra o uso de parâmetros out usando a sintaxe introduzida no C# 7.The following example shows the use of out parameters using the syntax introduced in C# 7.

static void Divide(int x, int y, out int result, out int remainder)
{
    result = x / y;
    remainder = x % y;
}

public static void OutUsage()
{
    Divide(10, 3, out int res, out int rem);
    Console.WriteLine($"{res} {rem}");	// "3 1"
}

Uma matriz de parâmetros permite que um número variável de argumentos sejam passados para um método.A parameter array permits a variable number of arguments to be passed to a method. Uma matriz de parâmetro é declarada com o modificador params.A parameter array is declared with the params modifier. Somente o último parâmetro de um método pode ser uma matriz de parâmetros e o tipo de uma matriz de parâmetros deve ser um tipo de matriz unidimensional.Only the last parameter of a method can be a parameter array, and the type of a parameter array must be a single-dimensional array type. Os Write WriteLine métodos e da System.Console classe são bons exemplos de uso de matriz de parâmetros.The Write and WriteLine methods of the System.Console class are good examples of parameter array usage. Eles são declarados da seguinte maneira.They're declared as follows.

public class Console
{
    public static void Write(string fmt, params object[] args) { }
    public static void WriteLine(string fmt, params object[] args) { }
    // ...
}

Dentro de um método que usa uma matriz de parâmetros, a matriz de parâmetros se comporta exatamente como um parâmetro regular de um tipo de matriz.Within a method that uses a parameter array, the parameter array behaves exactly like a regular parameter of an array type. No entanto, em uma invocação de um método com uma matriz de parâmetros, é possível passar um único argumento do tipo de matriz de parâmetro ou qualquer número de argumentos do tipo de elemento da matriz de parâmetros.However, in an invocation of a method with a parameter array, it's possible to pass either a single argument of the parameter array type or any number of arguments of the element type of the parameter array. No último caso, uma instância de matriz é automaticamente criada e inicializada com os argumentos determinados.In the latter case, an array instance is automatically created and initialized with the given arguments. Esse exemploThis example

int x, y, z;
x = 3;
y = 4;
z = 5;
Console.WriteLine("x={0} y={1} z={2}", x, y, z);

é equivalente ao escrito a seguir.is equivalent to writing the following.

int x = 3, y = 4, z = 5;

string s = "x={0} y={1} z={2}";
object[] args = new object[3];
args[0] = x;
args[1] = y;
args[2] = z;
Console.WriteLine(s, args);

Corpo do método e variáveis locaisMethod body and local variables

Um corpo do método especifica as instruções para execução quando o método é invocado.A method’s body specifies the statements to execute when the method is invoked.

Um corpo de método pode declarar variáveis que são específicas para a invocação do método.A method body can declare variables that are specific to the invocation of the method. Essas variáveis são chamadas de variáveis locais.Such variables are called local variables. Uma declaração de variável local especifica um nome de tipo, um nome de variável e, possivelmente, um valor inicial.A local variable declaration specifies a type name, a variable name, and possibly an initial value. O exemplo a seguir declara uma variável local i com um valor inicial de zero e uma variável local j sem valor inicial.The following example declares a local variable i with an initial value of zero and a local variable j with no initial value.

class Squares
{
    public static void WriteSquares()
    {
        int i = 0;
        int j;
        while (i < 10)
        {
            j = i * i;
            Console.WriteLine($"{i} x {i} = {j}");
            i = i + 1;
        }
    }
}

O C# requer que uma variável local seja atribuída definitivamente antes de seu valor poder ser obtido.C# requires a local variable to be definitely assigned before its value can be obtained. Por exemplo, se a declaração do anterior i não incluísse um valor inicial, o compilador relataria um erro para os usos mais recentes do porque não seria i i definitivamente atribuído a esses pontos no programa.For example, if the declaration of the previous i didn't include an initial value, the compiler would report an error for the later usages of i because i wouldn't be definitely assigned at those points in the program.

Um método pode usar instruções return para retornar o controle é pelo chamador.A method can use return statements to return control to its caller. Em um método que retorna void , as return instruções não podem especificar uma expressão.In a method returning void, return statements can't specify an expression. Em um método que retorna não nulo, as instruções return devem incluir uma expressão que calcula o valor retornado.In a method returning non-void, return statements must include an expression that computes the return value.

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

Um método declarado com um static modificador é um método estático.A method declared with a static modifier is a static method. Um método estático não opera em uma instância específica e só pode acessar diretamente membros estáticos.A static method doesn't operate on a specific instance and can only directly access static members.

Um método declarado sem um static modificador é um método de instância.A method declared without a static modifier is an instance method. Um método de instância opera em uma instância específica e pode acessar membros estáticos e de instância.An instance method operates on a specific instance and can access both static and instance members. A instância em que um método de instância foi invocado pode ser explicitamente acessada como this.The instance on which an instance method was invoked can be explicitly accessed as this. É um erro fazer referência a this um método estático.It's an error to refer to this in a static method.

A seguinte classe Entity tem membros estáticos e de instância.The following Entity class has both static and instance members.

class Entity
{
    static int s_nextSerialNo;
    int _serialNo;
    
    public Entity()
    {
        _serialNo = s_nextSerialNo++;
    }
    
    public int GetSerialNo()
    {
        return _serialNo;
    }
    
    public static int GetNextSerialNo()
    {
        return s_nextSerialNo;
    }
    
    public static void SetNextSerialNo(int value)
    {
        s_nextSerialNo = value;
    }
}

Cada Entity instância contém um número de série (e, presumivelmente, algumas outras informações que não são mostradas aqui).Each Entity instance contains a serial number (and presumably some other information that isn't shown here). O construtor Entity (que é como um método de instância) inicializa a nova instância com o próximo número de série disponível.The Entity constructor (which is like an instance method) initializes the new instance with the next available serial number. Como o construtor é um membro de instância, ele tem permissão para acessar o _serialNo campo de instância e o s_nextSerialNo campo estático.Because the constructor is an instance member, it's permitted to access both the _serialNo instance field and the s_nextSerialNo static field.

Os métodos estáticos GetNextSerialNo e SetNextSerialNo podem acessar o campo estático s_nextSerialNo, mas seria um erro para eles acessar diretamente o campo de instância _serialNo.The GetNextSerialNo and SetNextSerialNo static methods can access the s_nextSerialNo static field, but it would be an error for them to directly access the _serialNo instance field.

O exemplo a seguir mostra o uso da Entity classe.The following example shows the use of the Entity class.

Entity.SetNextSerialNo(1000);
Entity e1 = new Entity();
Entity e2 = new Entity();
Console.WriteLine(e1.GetSerialNo());          // Outputs "1000"
Console.WriteLine(e2.GetSerialNo());          // Outputs "1001"
Console.WriteLine(Entity.GetNextSerialNo());  // Outputs "1002"

Os SetNextSerialNo GetNextSerialNo métodos estáticos e são invocados na classe, enquanto o GetSerialNo método de instância é invocado em instâncias da classe.The SetNextSerialNo and GetNextSerialNo static methods are invoked on the class whereas the GetSerialNo instance method is invoked on instances of the class.

Métodos abstratos, virtuais e de substituiçãoVirtual, override, and abstract methods

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

Quando um método virtual é invocado, o tipo de tempo de execução da instância para o qual essa invocação ocorre determina a implementação real do método para invocar.When a virtual method is invoked, 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 nonvirtual method invocation, the compile-time type of the instance is the determining factor.

Um método virtual pode ser substituído em uma classe derivada.A virtual method can be overridden in a derived class. Quando uma declaração de método de instância inclui um modificador de substituição, o método substitui um método virtual herdado com a mesma assinatura.When an instance method declaration includes an override modifier, the method overrides an inherited virtual method with the same signature. Uma declaração de método virtual apresenta um novo método.A virtual method declaration introduces a new method. Uma declaração de método de substituição especializa um método virtual herdado existente fornecendo uma nova implementação desse método.An override method declaration specializes an existing inherited virtual method by providing a new implementation of that method.

Um método abstrato é um método virtual sem implementação.An abstract method is a virtual method with no implementation. Um método abstract é declarado com o abstract modificador e é permitido somente em uma classe abstrata.An abstract method is declared with the abstract modifier and is permitted only in an abstract class. Um método abstrato deve ser substituído em cada classe derivada não abstrata.An abstract method must be overridden in every non-abstract derived class.

O exemplo a seguir declara uma classe abstrata, Expression, que representa um nó de árvore de expressão e três classes derivadas, Constant, VariableReference e Operation, que implementam nós de árvore de expressão para operações aritméticas, referências de variável e constantes.The following example declares an abstract class, Expression, which represents an expression tree node, and three derived classes, Constant, VariableReference, and Operation, which implement expression tree nodes for constants, variable references, and arithmetic operations. (Este exemplo é semelhante a, mas não relacionado aos tipos de árvore de expressão).(This example is similar to, but not related to the expression tree types).

public abstract class Expression
{
    public abstract double Evaluate(Dictionary<string, object> vars);
}

public class Constant : Expression
{
    double _value;
    
    public Constant(double value)
    {
        _value = value;
    }
    
    public override double Evaluate(Dictionary<string, object> vars)
    {
        return _value;
    }
}

public class VariableReference : Expression
{
    string _name;
    
    public VariableReference(string name)
    {
        _name = name;
    }
    
    public override double Evaluate(Dictionary<string, object> vars)
    {
        object value = vars[_name] ?? throw new Exception($"Unknown variable: {_name}");
        return Convert.ToDouble(value);
    }
}

public class Operation : Expression
{
    Expression _left;
    char _op;
    Expression _right;
    
    public Operation(Expression left, char op, Expression right)
    {
        _left = left;
        _op = op;
        _right = right;
    }
    
    public override double Evaluate(Dictionary<string, object> vars)
    {
        double x = _left.Evaluate(vars);
        double y = _right.Evaluate(vars);
        switch (_op)
        {
            case '+': return x + y;
            case '-': return x - y;
            case '*': return x * y;
            case '/': return x / y;
            
            default: throw new Exception("Unknown operator");
        }
    }
}

As quatro classes anteriores podem ser usadas para modelar expressões aritméticas.The previous four classes can be used to model arithmetic expressions. Por exemplo, usando instâncias dessas classes, a expressão x + 3 pode ser representada da seguinte maneira.For example, using instances of these classes, the expression x + 3 can be represented as follows.

Expression e = new Operation(
    new VariableReference("x"),
    '+',
    new Constant(3));

O método Evaluate de uma instância Expression é chamado para avaliar a expressão especificada e produzir um valor double.The Evaluate method of an Expression instance is invoked to evaluate the given expression and produce a double value. O método recebe um argumento Dictionary que contém nomes de variáveis (como chaves das entradas) e valores (como valores das entradas).The method takes a Dictionary argument that contains variable names (as keys of the entries) and values (as values of the entries). Como Evaluate é um método abstrato, classes não abstratas derivadas de Expression devem substituir Evaluate.Because Evaluate is an abstract method, non-abstract classes derived from Expression must override Evaluate.

Uma implementação de Evaluate do Constant retorna apenas a constante armazenada.A Constant's implementation of Evaluate simply returns the stored constant. Uma implementação de VariableReference consulta o nome de variável no dicionário e retorna o valor resultante.A VariableReference's implementation looks up the variable name in the dictionary and returns the resulting value. Uma implementação de Operation primeiro avalia os operandos esquerdo e direito (chamando recursivamente seus métodos Evaluate) e, em seguida, executa a operação aritmética determinada.An Operation's implementation first evaluates the left and right operands (by recursively invoking their Evaluate methods) and then performs the given arithmetic operation.

O seguinte programa usa as classes Expression para avaliar a expressão x * (y + 2) para valores diferentes de x e y.The following program uses the Expression classes to evaluate the expression x * (y + 2) for different values of x and y.

Expression e = new Operation(
    new VariableReference("x"),
    '*',
    new Operation(
        new VariableReference("y"),
        '+',
        new Constant(2)
    )
);
Dictionary<string, object> vars = new Dictionary<string, object>();
vars["x"] = 3;
vars["y"] = 5;
Console.WriteLine(e.Evaluate(vars)); // "21"
vars["x"] = 1.5;
vars["y"] = 9;
Console.WriteLine(e.Evaluate(vars)); // "16.5"

Sobrecarga de métodoMethod overloading

A sobrecarga de método permite que vários métodos na mesma classe tenham o mesmo nome, contanto que tenham assinaturas exclusivas.Method overloading permits multiple methods in the same class to have the same name as long as they have unique signatures. Ao compilar uma invocação de um método sobrecarregado, o compilador usa a resolução de sobrecarga para determinar o método específico para invocar.When compiling an invocation of an overloaded method, the compiler uses overload resolution to determine the specific method to invoke. A resolução de sobrecarga encontra um método que melhor corresponde aos argumentos.Overload resolution finds the one method that best matches the arguments. Se não for possível encontrar uma única melhor correspondência, um erro será relatado.If no single best match can be found, an error is reported. O exemplo a seguir mostra a resolução de sobrecarga em vigor.The following example shows overload resolution in effect. O comentário para cada invocação no UsageExample método mostra qual método é invocado.The comment for each invocation in the UsageExample method shows which method is invoked.

class OverloadingExample
{
    static void F() => Console.WriteLine("F()");
    static void F(object x) => Console.WriteLine("F(object)");
    static void F(int x) => Console.WriteLine("F(int)");
    static void F(double x) => Console.WriteLine("F(double)");
    static void F<T>(T x) => Console.WriteLine("F<T>(T)");            
    static void F(double x, double y) => Console.WriteLine("F(double, double)");
    
    public static void UsageExample()
    {
        F();            // Invokes F()
        F(1);           // Invokes F(int)
        F(1.0);         // Invokes F(double)
        F("abc");       // Invokes F<string>(string)
        F((double)1);   // Invokes F(double)
        F((object)1);   // Invokes F(object)
        F<int>(1);      // Invokes F<int>(int)
        F(1, 1);        // Invokes F(double, double)
    }

Conforme mostrado pelo exemplo, um método específico sempre pode ser selecionado por meio da conversão explícita dos argumentos para os tipos de parâmetro e argumentos de tipo exatos.As shown by the example, a particular method can always be selected by explicitly casting the arguments to the exact parameter types and type arguments.

Outros membros da funçãoOther function members

Os membros que contêm código executável são conhecidos coletivamente como membros de função de uma classe.Members that contain executable code are collectively known as the function members of a class. A seção anterior descreve os métodos, que são os principais tipos de membros de função.The preceding section describes methods, which are the primary types of function members. Esta seção descreve os outros tipos de membros da função com suporte do C#: construtores, propriedades, indexadores, eventos, operadores e finalizadores.This section describes the other kinds of function members supported by C#: constructors, properties, indexers, events, operators, and finalizers.

O exemplo a seguir mostra uma classe genérica chamada MyList<T> , que implementa uma lista de objetos que aumenta.The following example shows a generic class called MyList<T>, which implements a growable list of objects. A classe contém vários exemplos dos tipos mais comuns de membros da função.The class contains several examples of the most common kinds of function members.

public class MyList<T>
{
    const int DefaultCapacity = 4;

    T[] _items;
    int _count;

    public MyList(int capacity = DefaultCapacity)
    {
        _items = new T[capacity];
    }

    public int Count => _count;

    public int Capacity
    {
        get =>  _items.Length;
        set
        {
            if (value < _count) value = _count;
            if (value != _items.Length)
            {
                T[] newItems = new T[value];
                Array.Copy(_items, 0, newItems, 0, _count);
                _items = newItems;
            }
        }
    }

    public T this[int index]
    {
        get => _items[index];
        set
        {
            _items[index] = value;
            OnChanged();
        }
    }

    public void Add(T item)
    {
        if (_count == Capacity) Capacity = _count * 2;
        _items[_count] = item;
        _count++;
        OnChanged();
    }
    protected virtual void OnChanged() =>
        Changed?.Invoke(this, EventArgs.Empty);

    public override bool Equals(object other) =>
        Equals(this, other as MyList<T>);

    static bool Equals(MyList<T> a, MyList<T> b)
    {
        if (Object.ReferenceEquals(a, null)) return Object.ReferenceEquals(b, null);
        if (Object.ReferenceEquals(b, null) || a._count != b._count)
            return false;
        for (int i = 0; i < a._count; i++)
        {
            if (!object.Equals(a._items[i], b._items[i]))
            {
                return false;
            }
        }
        return true;
    }

    public event EventHandler Changed;

    public static bool operator ==(MyList<T> a, MyList<T> b) =>
        Equals(a, b);

    public static bool operator !=(MyList<T> a, MyList<T> b) =>
        !Equals(a, b);
}

ConstrutoresConstructors

O C# dá suporte aos construtores estáticos e de instância.C# supports both instance and static 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. Um construtor estático é um membro que implementa as ações necessárias para inicializar uma classe em si quando ela é carregada pela primeira vez.A static constructor is a member that implements the actions required to initialize a class itself when it's first loaded.

Um construtor é declarado como um método sem nenhum tipo de retorno e o mesmo nome que a classe continente.A constructor is declared like a method with no return type and the same name as the containing class. Se uma declaração de Construtor incluir um static modificador, ele declara um construtor estático.If a constructor declaration includes a static modifier, it declares a static constructor. Caso contrário, ela declara um construtor de instância.Otherwise, it declares an instance constructor.

Construtores de instância podem ser sobrecarregados e ter parâmetros opcionais.Instance constructors can be overloaded and can have optional parameters. Por exemplo, a classe MyList<T> declara um construtor de instância com um único parâmetro int opcional.For example, the MyList<T> class declares one instance constructor with a single optional int parameter. Os construtores de instância são invocados usando o operador new.Instance constructors are invoked using the new operator. As seguintes instruções alocam duas instâncias MyList<string> usando o construtor da classe MyList com e sem o argumento opcional.The following statements allocate two MyList<string> instances using the constructor of the MyList class with and without the optional argument.

MyList<string> list1 = new MyList<string>();
MyList<string> list2 = new MyList<string>(10);

Ao contrário de outros membros, os construtores de instância não são herdados.Unlike other members, instance constructors aren't inherited. Uma classe não tem construtores de instância diferentes dos construtores realmente declarados na classe.A class has no instance constructors other than those constructors actually declared in the class. Se nenhum construtor de instância for fornecido para uma classe, então um construtor vazio sem parâmetros será fornecido automaticamente.If no instance constructor is supplied for a class, then an empty one with no parameters is automatically provided.

PropriedadesProperties

As propriedades são uma extensão natural dos campos.Properties are a natural extension of fields. Elas são denominadas membros com tipos associados, e a sintaxe para acessar os campos e as propriedades é a mesma.Both are named members with associated types, and the syntax for accessing fields and properties is the same. No entanto, ao contrário dos campos, as propriedades não denotam locais de armazenamento.However, unlike fields, properties don't denote storage locations. Em vez disso, as propriedades têm acessadores que especificam as instruções executadas quando seus valores são lidos ou gravados.Instead, properties have accessors that specify the statements executed when their values are read or written.

Uma propriedade é declarada como um campo, exceto que a declaração termina com um acessador get ou um acessador set gravado entre os delimitadores { e } em vez de terminar em um ponto e vírgula.A property is declared like a field, except that the declaration ends with a get accessor or a set accessor written between the delimiters { and } instead of ending in a semicolon. Uma propriedade que tem um acessador get e um acessador set é uma propriedade de leitura-gravação. Uma propriedade que tem apenas um acessador get é uma propriedade somente leitura, e uma propriedade que tem apenas um acessador set é uma propriedade somente gravação.A property that has both a get accessor and a set accessor is a read-write property, a property that has only a get accessor is a read-only property, and a property that has only a set accessor is a write-only property.

Um acessador get corresponde a um método sem parâmetros com um valor retornado do tipo de propriedade.A get accessor corresponds to a parameterless method with a return value of the property type. Um acessador set corresponde a um método com um parâmetro único chamado valor e nenhum tipo de retorno.A set accessor corresponds to a method with a single parameter named value and no return type. O acessador get computa o valor da propriedade.The get accessor computes the value of the property. O acessador set fornece um novo valor para a propriedade.The set accessor provides a new value for the property. Quando a propriedade é o destino de uma atribuição, ou o operando de ++ ou -- , o acessador set é invocado.When the property is the target of an assignment, or the operand of ++ or --, the set accessor is invoked. Em outros casos em que a propriedade é referenciada, o acessador get é invocado.In other cases where the property is referenced, the get accessor is invoked.

A classe MyList<T> declara duas propriedades, Count e Capacity, que são somente leitura e leitura/gravação, respectivamente.The MyList<T> class declares two properties, Count and Capacity, which are read-only and read-write, respectively. O código a seguir é um exemplo de uso dessas propriedades:The following code is an example of use of these properties:

MyList<string> names = new MyList<string>();
names.Capacity = 100;   // Invokes set accessor
int i = names.Count;    // Invokes get accessor
int j = names.Capacity; // Invokes get accessor

Como nos campos e métodos, o C# dá suporte a propriedades de instância e a propriedades estáticas.Similar to fields and methods, C# supports both instance properties and static properties. As propriedades estáticas são declaradas com o modificador estático e as propriedades de instância são declaradas sem ele.Static properties are declared with the static modifier, and instance properties are declared without it.

Os acessadores de uma propriedade podem ser virtuais.The accessor(s) of a property can be virtual. Quando uma declaração de propriedade inclui um modificador virtual, abstract ou override, ela se aplica aos acessadores da propriedade.When a property declaration includes a virtual, abstract, or override modifier, it applies to the accessor(s) of the property.

IndexadoresIndexers

Um indexador é um membro que permite que objetos sejam indexados da mesma forma que uma matriz.An indexer is a member that enables objects to be indexed in the same way as an array. Um indexador é declarado como uma propriedade, exceto se o nome do membro for this seguido por uma lista de parâmetros escrita entre os delimitadores [ e ].An indexer is declared like a property except that the name of the member is this followed by a parameter list written between the delimiters [ and ]. Os parâmetros estão disponíveis nos acessadores do indexador.The parameters are available in the accessor(s) of the indexer. Semelhante às propriedades, os indexadores podem ser de leitura-gravação, somente leitura e somente gravação, e os acessadores de um indexador pode ser virtuais.Similar to properties, indexers can be read-write, read-only, and write-only, and the accessor(s) of an indexer can be virtual.

A classe MyList<T> declara um indexador único de leitura-gravação que usa um parâmetro int.The MyList<T> class declares a single read-write indexer that takes an int parameter. O indexador possibilita indexar instâncias MyList<T> com valores int.The indexer makes it possible to index MyList<T> instances with int values. Por exemplo:For example:

MyList<string> names = new MyList<string>();
names.Add("Liz");
names.Add("Martha");
names.Add("Beth");
for (int i = 0; i < names.Count; i++)
{
    string s = names[i];
    names[i] = s.ToUpper();
}

Os indexadores podem ser sobrecarregados.Indexers can be overloaded. Uma classe pode declarar vários indexadores, desde que o número ou os tipos de seus parâmetros sejam diferentes.A class can declare multiple indexers as long as the number or types of their parameters differ.

EventosEvents

Um evento é um membro que permite que uma classe ou objeto forneça notificações.An event is a member that enables a class or object to provide notifications. Um evento é declarado como um campo, exceto que a declaração inclui uma event palavra-chave e o tipo deve ser um tipo delegado.An event is declared like a field except that the declaration includes an event keyword and the type must be a delegate type.

Dentro de uma classe que declara um membro de evento, o evento se comporta exatamente como um campo de um tipo delegado (desde que o evento não seja abstrato e não declare acessadores).Within a class that declares an event member, the event behaves just like a field of a delegate type (provided the event isn't abstract and doesn't declare accessors). O campo armazena uma referência a um delegado que representa os manipuladores de eventos que foram adicionados ao evento.The field stores a reference to a delegate that represents the event handlers that have been added to the event. Se nenhum manipulador de evento estiver presente, o campo será null.If no event handlers are present, the field is null.

A classe MyList<T> declara um membro único de evento chamado Changed, que indica que um novo item foi adicionado à lista.The MyList<T> class declares a single event member called Changed, which indicates that a new item has been added to the list. O evento Alterado é gerado pelo método virtual OnChanged, que primeiro verifica se o evento é null (o que significa que nenhum manipulador está presente).The Changed event is raised by the OnChanged virtual method, which first checks whether the event is null (meaning that no handlers are present). A noção de gerar um evento é precisamente equivalente a invocar o delegado representado pelo evento.The notion of raising an event is precisely equivalent to invoking the delegate represented by the event. Não há construções de linguagem especiais para gerar eventos.There are no special language constructs for raising events.

Os clientes reagem a eventos por meio de manipuladores de eventos.Clients react to events through event handlers. Os manipuladores de eventos são conectados usando o operador += e removidos usando o operador -=.Event handlers are attached using the += operator and removed using the -= operator. O exemplo a seguir anexa um manipulador de eventos para o evento Changed de um MyList<string>.The following example attaches an event handler to the Changed event of a MyList<string>.

class EventExample
{
    static int s_changeCount;
    
    static void ListChanged(object sender, EventArgs e)
    {
        s_changeCount++;
    }
    
    public static void Usage()
    {
        var names = new MyList<string>();
        names.Changed += new EventHandler(ListChanged);
        names.Add("Liz");
        names.Add("Martha");
        names.Add("Beth");
        Console.WriteLine(s_changeCount); // "3"
    }
}

Para cenários avançados em que o controle do armazenamento subjacente de um evento é desejado, uma declaração de evento pode fornecer explicitamente e acessadores add remove , que são semelhantes ao set acessador de uma propriedade.For advanced scenarios where control of the underlying storage of an event is desired, an event declaration can explicitly provide add and remove accessors, which are similar to the set accessor of a property.

OperadoresOperators

Um operador é um membro que define o significado da aplicação de um operador de expressão específico para instâncias de uma classe.An operator is a member that defines the meaning of applying a particular expression operator to instances of a class. Três tipos de operadores podem ser definidos: operadores unários, operadores binários e operadores de conversão.Three kinds of operators can be defined: unary operators, binary operators, and conversion operators. Todos os operadores devem ser declarados como public e static.All operators must be declared as public and static.

A MyList<T> classe declara dois operadores operator == e operator != .The MyList<T> class declares two operators, operator == and operator !=. Esses operadores substituídos dão um novo significado a expressões que aplicam esses operadores a MyList instâncias.These overridden operators give new meaning to expressions that apply those operators to MyList instances. Especificamente, os operadores definem a igualdade de duas MyList<T> instâncias como comparar cada um dos objetos contidos usando seus Equals métodos.Specifically, the operators define equality of two MyList<T> instances as comparing each of the contained objects using their Equals methods. O exemplo a seguir usa o operador == para comparar duas instâncias MyList<int>.The following example uses the == operator to compare two MyList<int> instances.

MyList<int> a = new MyList<int>();
a.Add(1);
a.Add(2);
MyList<int> b = new MyList<int>();
b.Add(1);
b.Add(2);
Console.WriteLine(a == b);  // Outputs "True"
b.Add(3);
Console.WriteLine(a == b);  // Outputs "False"

O primeiro Console.WriteLine gera True porque as duas listas contêm o mesmo número de objetos com os mesmos valores na mesma ordem.The first Console.WriteLine outputs True because the two lists contain the same number of objects with the same values in the same order. Como MyList<T> não definiu operator ==, o primeiro Console.WriteLine geraria False porque a e b referenciam diferentes instâncias MyList<int>.Had MyList<T> not defined operator ==, the first Console.WriteLine would have output False because a and b reference different MyList<int> instances.

FinalizadoresFinalizers

Um finalizador é um membro que implementa as ações necessárias para finalizar uma instância de uma classe.A finalizer is a member that implements the actions required to finalize an instance of a class. Normalmente, um finalizador é necessário para liberar recursos não gerenciados.Typically, a finalizer is needed to release unmanaged resources. Os finalizadores não podem ter parâmetros, eles não podem ter modificadores de acessibilidade e não podem ser invocados explicitamente.Finalizers can't have parameters, they can't have accessibility modifiers, and they can't be invoked explicitly. O finalizador de uma instância é invocado automaticamente durante a coleta de lixo.The finalizer for an instance is invoked automatically during garbage collection. Para obter mais detalhes, consulte o artigo sobre finalizadores.For more details, see the article on finalizers.

O coletor de lixo tem latitude ampla ao decidir quando coletar objetos e executar os finalizadores.The garbage collector is allowed wide latitude in deciding when to collect objects and run finalizers. Especificamente, o tempo das invocações do finalizador não é determinístico e os finalizadores podem ser executados em qualquer thread.Specifically, the timing of finalizer invocations isn't deterministic, and finalizers may be executed on any thread. Para esses e outros motivos, as classes devem implementar os finalizadores apenas quando não houver outras soluções viáveis.For these and other reasons, classes should implement finalizers only when no other solutions are feasible.

A instrução using fornece uma abordagem melhor para a destruição de objetos.The using statement provides a better approach to object destruction.

ExpressõesExpressions

Expressões são construídas a partir de operandos e operadores.Expressions are constructed from operands and operators. Os operadores de uma expressão indicam quais operações devem ser aplicadas aos operandos.The operators of an expression indicate which operations to apply to the operands. Exemplos de operadores incluem +, -, *, / e new.Examples of operators include +, -, *, /, and new. Exemplos de operandos incluem literais, campos, variáveis locais e expressões.Examples of operands include literals, fields, local variables, and expressions.

Quando uma expressão contém vários operadores, a precedência dos operadores controla a ordem na qual os operadores individuais são avaliados.When an expression contains multiple operators, the precedence of the operators controls the order in which the individual operators are evaluated. Por exemplo, a expressão x + y * z é avaliada como x + (y * z) porque o operador * tem precedência maior do que o operador +.For example, the expression x + y * z is evaluated as x + (y * z) because the * operator has higher precedence than the + operator.

Quando ocorre um operando entre dois operadores com a mesma precedência, a associatividade dos operadores controla a ordem na qual as operações são executadas:When an operand occurs between two operators with the same precedence, the associativity of the operators controls the order in which the operations are performed:

  • Exceto para os operadores de atribuição e de União nulo, todos os operadores binários são associativos à esquerda, o que significa que as operações são executadas da esquerda para a direita.Except for the assignment and null-coalescing operators, all binary operators are left-associative, meaning that operations are performed from left to right. Por exemplo, x + y + z é avaliado como (x + y) + z.For example, x + y + z is evaluated as (x + y) + z.
  • Os operadores de atribuição, a União nula ?? e ??= os operadores e o operador condicional ?: são associativos à direita, o que significa que as operações são executadas da direita para a esquerda.The assignment operators, the null-coalescing ?? and ??= operators, and the conditional operator ?: are right-associative, meaning that operations are performed from right to left. Por exemplo, x = y = z é avaliado como x = (y = z).For example, x = y = z is evaluated as x = (y = z).

Precedência e associatividade podem ser controladas usando parênteses.Precedence and associativity can be controlled using parentheses. Por exemplo, x + y * z primeiro multiplica y por z e, em seguida, adiciona o resultado a x, mas (x + y) * z primeiro adiciona x e y e, em seguida, multiplica o resultado por z.For example, x + y * z first multiplies y by z and then adds the result to x, but (x + y) * z first adds x and y and then multiplies the result by z.

A maioria dos operadores pode ser sobrecarregada.Most operators can be overloaded. A sobrecarga de operador permite que implementações de operador definidas pelo usuário sejam especificadas para operações em que um ou ambos os operandos são de um tipo struct ou de classe definida pelo usuário.Operator overloading permits user-defined operator implementations to be specified for operations where one or both of the operands are of a user-defined class or struct type.

C# fornece uma série de operadores para realizar operações aritméticas, lógicas, bit a bit e shift e comparações de igualdade e ordem.C# provides a number of operators to perform arithmetic, logical, bitwise and shift operations and equality and order comparisons.

Para obter a lista completa de operadores do C# ordenada pelo nível de precedência, confira Operadores do C#.For the complete list of C# operators ordered by precedence level, see C# operators.

InstruçõesStatements

As ações de um programa são expressas usando instruções.The actions of a program are expressed using statements. O C# oferece suporte a vários tipos diferentes de instruções, algumas delas definidas em termos de instruções inseridas.C# supports several different kinds of statements, a number of which are defined in terms of embedded statements.

  • Um bloco permite a produção de várias instruções em contextos nos quais uma única instrução é permitida.A block permits multiple statements to be written in contexts where a single statement is allowed. Um bloco é composto por uma lista de instruções escritas entre os delimitadores { e }.A block consists of a list of statements written between the delimiters { and }.
  • Instruções de declaração são usadas para declarar constantes e variáveis locais.Declaration statements are used to declare local variables and constants.
  • Instruções de expressão são usadas para avaliar expressões.Expression statements are used to evaluate expressions. As expressões que podem ser usadas como instruções incluem chamadas de método, alocações de objeto usando o operador new, atribuições usando = e os operadores de atribuição compostos, operações de incremento e decremento usando os operadores ++ e -- e as expressões await.Expressions that can be used as statements include method invocations, object allocations using the new operator, assignments using = and the compound assignment operators, increment and decrement operations using the ++ and -- operators and await expressions.
  • Instruções de seleção são usadas para selecionar uma dentre várias instruções possíveis para execução com base no valor de alguma expressão.Selection statements are used to select one of a number of possible statements for execution based on the value of some expression. Esse grupo contém as if switch instruções e.This group contains the if and switch statements.
  • Instruções de iteração são usadas para executar repetidamente uma instrução inserida.Iteration statements are used to execute repeatedly an embedded statement. Esse grupo contém as while do instruções,, for e foreach .This group contains the while, do, for, and foreach statements.
  • Instruções de salto são usadas para transferir o controle.Jump statements are used to transfer control. Esse grupo contém as break continue instruções,, goto ,, throw return e yield .This group contains the break, continue, goto, throw, return, and yield statements.
  • A instrução try... catch é usada para capturar exceções que ocorrem durante a execução de um bloco, e a instrução try... finally é usada para especificar o código de finalização que é executado sempre, se uma exceção ocorrer ou não.The try...catch statement is used to catch exceptions that occur during execution of a block, and the try...finally statement is used to specify finalization code that is always executed, whether an exception occurred or not.
  • As instruções checked e unchecked são usadas para controlar o contexto de verificação de estouro para operações e conversões aritméticas do tipo integral.The checked and unchecked statements are used to control the overflow-checking context for integral-type arithmetic operations and conversions.
  • A instrução lock é usada para obter o bloqueio de exclusão mútua para um determinado objeto, executar uma instrução e, em seguida, liberar o bloqueio.The lock statement is used to obtain the mutual-exclusion lock for a given object, execute a statement, and then release the lock.
  • A instrução using é usada para obter um recurso, executar uma instrução e, em seguida, descartar esse recurso.The using statement is used to obtain a resource, execute a statement, and then dispose of that resource.

O seguinte lista os tipos de instruções que podem ser usadas:The following lists the kinds of statements that can be used:

  • Declaração de variável local.Local variable declaration.
  • Declaração de constante local.Local constant declaration.
  • Instrução de expressão.Expression statement.
  • if privacidade.if statement.
  • switch privacidade.switch statement.
  • while privacidade.while statement.
  • do privacidade.do statement.
  • for privacidade.for statement.
  • foreach privacidade.foreach statement.
  • break privacidade.break statement.
  • continue privacidade.continue statement.
  • goto privacidade.goto statement.
  • return privacidade.return statement.
  • yield privacidade.yield statement.
  • throw instruções e try instruções.throw statements and try statements.
  • checked``uncheckedinstruções and.checked and unchecked statements.
  • lock privacidade.lock statement.
  • using privacidade.using statement.