Introdução às classes

Tipos de referência

Um tipo que é definido como uma class é um tipo de referência. No tempo de execução, quando você declara uma variável de um tipo de referência, a variável contém o valor null até que você crie explicitamente uma instância da classe usando o operador new ou atribua a ela um objeto de um tipo compatível que foi criado em outro lugar, conforme mostrado no exemplo a seguir:

//Declaring an object of type MyClass.
MyClass mc = new MyClass();

//Declaring another object of the same type, assigning it the value of the first object.
MyClass mc2 = mc;

Quando o objeto é criado, memória suficiente é alocada no heap gerenciado para o objeto específico, e a variável contém apenas uma referência para o local do objeto. A memória usada por um objeto é recuperada pela funcionalidade de gerenciamento automático de memória do CLR, que é conhecida como coleta de lixo. Para obter mais informações sobre a coleta de lixo, consulte Gerenciamento automático de memória e coleta de lixo.

Declarando classes

As classes são declaradas usando a palavra-chave class, seguida por um identificador exclusivo, conforme mostrado no exemplo a seguir:

//[access modifier] - [class] - [identifier]
public class Customer
{
   // Fields, properties, methods and events go here...
}

Um modificador de acesso opcional precede a palavra-chave class. Como public é usado nesse caso, qualquer pessoa pode criar instâncias dessa classe. O nome da classe segue a palavra-chave class. O nome da classe deve ser um nome do identificador válido em C#. O restante da definição é o corpo da classe, em que o comportamento e os dados são definidos. Campos, propriedades, métodos e eventos em uma classe são coletivamente denominados de membros de classe.

Criando objetos

Embora eles sejam usados algumas vezes de maneira intercambiável, uma classe e um objeto são coisas diferentes. Uma classe define um tipo de objeto, mas não é um objeto em si. Um objeto é uma entidade concreta com base em uma classe e, às vezes, é conhecido como uma instância de uma classe.

Os objetos podem ser criados usando a palavra-chave new seguida pelo nome da classe, dessa maneira:

Customer object1 = new Customer();

Quando uma instância de uma classe é criada, uma referência ao objeto é passada de volta para o programador. No exemplo anterior, object1 é uma referência a um objeto que é baseado em Customer. Esta referência refere-se ao novo objeto, mas não contém os dados de objeto. Na verdade, você pode criar uma referência de objeto sem criar um objeto:

Customer object2;

Não recomendamos a criação de referências de objeto, que não faz referência a um objeto, porque tentar acessar um objeto por meio de uma referência desse tipo falhará em tempo de execução. Uma referência pode ser feita para se referir a um objeto, criando um novo objeto ou atribuindo-a a um objeto existente, como abaixo:

Customer object3 = new Customer();
Customer object4 = object3;

Esse código cria duas referências de objeto que fazem referência ao mesmo objeto. Portanto, qualquer alteração no objeto feita por meio de object3 será refletida no usos posteriores de object4. Como os objetos que são baseados em classes são referenciados por referência, as classes são conhecidas como tipos de referência.

Construtores e inicialização

As seções anteriores introduziram a sintaxe para declarar um tipo de classe e criar uma instância desse tipo. Ao criar uma instância de um tipo, você deseja garantir que seus campos e propriedades sejam inicializados para valores úteis. Há várias maneiras de inicializar valores:

  • Aceitar valores padrão
  • Inicializadores de campo
  • Parâmetros do construtor
  • Inicializadores de objeto

Cada tipo .NET tem um valor padrão. Normalmente, esse valor é 0 para tipos de número e null para todos os tipos de referência. Você pode contar com esse valor padrão quando for razoável em seu aplicativo.

Quando o padrão .NET não é o valor certo, você pode definir um valor inicial usando um inicializador de campo:

public class Container
{
    // Initialize capacity field to a default value of 10:
    private int _capacity = 10;
}

Você pode exigir que os chamadores forneçam um valor inicial definindo um construtor responsável por definir esse valor inicial:

public class Container
{
    private int _capacity;

    public Container(int capacity) => _capacity = capacity;
}

A partir do C# 12, você pode definir um construtor primário como parte da declaração de classe:

public class Container(int capacity)
{
    private int _capacity = capacity;
}

Adicionar parâmetros ao nome da classe define o construtor primário. Esses parâmetros estão disponíveis no corpo da classe, que inclui seus membros. Você pode usá-los para inicializar campos ou em qualquer outro lugar em que eles sejam necessários.

Você também pode usar o modificador required em uma propriedade e permitir que os chamadores usem um inicializador de objeto para definir o valor inicial da propriedade:

public class Person
{
    public required string LastName { get; set; }
    public required string FirstName { get; set; }
}

A adição da palavra-chave required determina que os chamadores devem definir essas propriedades como parte de uma expressão new:

var p1 = new Person(); // Error! Required properties not set
var p2 = new Person() { FirstName = "Grace", LastName = "Hopper" };

Herança de classe

As classes dão suporte completo à herança, uma característica fundamental da programação orientada a objetos. Quando você cria uma classe, é possível herdar de qualquer outra classe que não esteja definida como sealed. Outras classes podem herdar de sua classe e substituir métodos virtuais de classe. Além disso, você pode implementar uma ou mais interfaces.

A herança é realizada usando uma derivação, o que significa que uma classe é declarada usando uma classe base, da qual ela herda o comportamento e os dados. Uma classe base é especificada ao acrescentar dois-pontos e o nome de classe base depois do nome de classe derivada, dessa maneira:

public class Manager : Employee
{
    // Employee fields, properties, methods and events are inherited
    // New Manager fields, properties, methods and events go here...
}

Quando uma declaração de classe inclui uma classe base, ela herda todos os membros da classe base, exceto os construtores. Para obter mais informações, consulte Herança.

Uma classe no C# só pode herdar diretamente de uma classe base. No entanto, como uma classe base pode herdar de outra classe, uma classe pode herdar indiretamente várias classes base. Além disso, uma classe pode implementar diretamente uma ou mais interfaces. Para obter mais informações, consulte Interfaces.

Uma classe pode ser declarada como abstract. Uma classe abstrata contém métodos abstratos que têm uma definição de assinatura, mas não têm implementação. As classes abstratas não podem ser instanciadas. Elas só podem ser usadas por meio de classes derivadas que implementam os métodos abstratos. Por outro lado, uma classe lacrada não permite que outras classes sejam derivadas dela. Para obter mais informações, consulte Classes e Membros de Classes Abstratos e Lacrados.

As definições de classe podem ser divididas entre arquivos de origem diferentes. Para obter mais informações, consulte Classes parciais e métodos.

Especificação da Linguagem C#

Para obter mais informações, consulte a Especificação da linguagem C#. A especificação da linguagem é a fonte definitiva para a sintaxe e o uso de C#.