Compartilhar via


Objetos – criar instâncias de tipos

Uma definição de classe ou struct é como um blueprint que especifica o que o tipo pode fazer. Um objeto é basicamente um bloco de memória que foi alocado e configurado de acordo com o blueprint. Um programa pode criar muitos objetos da mesma classe. Os objetos também são chamados de instâncias e podem ser armazenados em uma variável nomeada ou em uma matriz ou coleção. Código do cliente é o código que usa essas variáveis para chamar os métodos e acessar as propriedades públicas do objeto. Em uma linguagem orientada a objetos, como C#, um programa típico consiste em vários objetos interagindo dinamicamente.

Observação

Os tipos estáticos se comportam de forma diferente do descrito aqui. Para obter mais informações, consulte Classes estáticas e membros de classe estática.

Instâncias Struct vs. Instâncias de classe

Como as classes são tipos de referência, uma variável de um objeto de classe contém uma referência ao endereço do objeto no heap gerenciado. Se uma segunda variável do mesmo tipo for atribuída à primeira variável, ambas as variáveis se referirão ao objeto nesse endereço. Este ponto é discutido com mais detalhes mais adiante neste artigo.

As instâncias de classes são criadas usando o new operador. No exemplo a seguir, Person é o tipo e person1 e person2 são instâncias ou objetos desse tipo.

using System;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
    // Other properties, methods, events...
}

class Program
{
    static void Main()
    {
        Person person1 = new Person("Leopold", 6);
        Console.WriteLine($"person1 Name = {person1.Name} Age = {person1.Age}");

        // Declare new person, assign person1 to it.
        Person person2 = person1;

        // Change the name of person2, and person1 also changes.
        person2.Name = "Molly";
        person2.Age = 16;

        Console.WriteLine($"person2 Name = {person2.Name} Age = {person2.Age}");
        Console.WriteLine($"person1 Name = {person1.Name} Age = {person1.Age}");
    }
}
/*
    Output:
    person1 Name = Leopold Age = 6
    person2 Name = Molly Age = 16
    person1 Name = Molly Age = 16
*/

Como os structs são tipos de valor, uma variável de um objeto struct contém uma cópia de todo o objeto. Instâncias de structs também podem ser criadas usando o new operador, mas isso não é necessário, conforme mostrado no exemplo a seguir:

using System;

namespace Example
{
    public struct Person
    {
        public string Name;
        public int Age;
        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }
    }

    public class Application
    {
        static void Main()
        {
            // Create  struct instance and initialize by using "new".
            // Memory is allocated on thread stack.
            Person p1 = new Person("Alex", 9);
            Console.WriteLine($"p1 Name = {p1.Name} Age = {p1.Age}");

            // Create  new struct object. Note that  struct can be initialized
            // without using "new".
            Person p2 = p1;

            // Assign values to p2 members.
            p2.Name = "Spencer";
            p2.Age = 7;
            Console.WriteLine($"p2 Name = {p2.Name} Age = {p2.Age}");

            // p1 values remain unchanged because p2 is  copy.
            Console.WriteLine($"p1 Name = {p1.Name} Age = {p1.Age}");
        }
    }
    /*
        Output:
        p1 Name = Alex Age = 9
        p2 Name = Spencer Age = 7
        p1 Name = Alex Age = 9
    */
}

A memória de p1 e p2 é alocada na pilha de thread. Essa memória é recuperada junto com o tipo ou método no qual ela é declarada. Esse é um dos motivos pelos quais os structs são copiados na atribuição. Por outro lado, a memória alocada a uma instância de classe é recuperada automaticamente (o lixo é coletado) pelo Common Language Runtime quando todas as referências ao objeto tiveram saído do escopo. Não é possível destruir deterministicamente um objeto de classe como você pode no C++. Para obter mais informações sobre a coleta de lixo no .NET, consulte Coleta de Lixo.

Observação

A alocação e a desalocação de memória no heap gerenciado é altamente otimizada no Common Language Runtime. Na maioria dos casos, não há uma diferença significativa quanto ao custo do desempenho de alocar uma instância da classe no heap em vez de alocar uma instância de struct na pilha.

Identidade do Objeto vs. Igualdade de Valor

Ao comparar dois objetos para igualdade, primeiro você deve distinguir se deseja saber se as duas variáveis representam o mesmo objeto na memória ou se os valores de um ou mais de seus campos são equivalentes. Se você pretende comparar valores, deve considerar se os objetos são instâncias de tipos de valor (structs) ou tipos de referência (classes, delegados, matrizes).

  • Para determinar se duas instâncias de classe se referem ao mesmo local na memória (o que significa que elas têm a mesma identidade), use o método estático Object.Equals . (System.Object é a classe base implícita para todos os tipos de valor e tipos de referência, incluindo structs e classes definidos pelo usuário.)

  • Para determinar se os campos de instância em duas instâncias de struct têm os mesmos valores, use o ValueType.Equals método. Como todos os structs herdam implicitamente de System.ValueType, você chama o método diretamente em seu objeto, conforme mostrado no exemplo a seguir:

    // Person is defined in the previous example.
    
    //public struct Person
    //{
    //    public string Name;
    //    public int Age;
    //    public Person(string name, int age)
    //    {
    //        Name = name;
    //        Age = age;
    //    }
    //}
    
    Person p1 = new Person("Wallace", 75);
    Person p2 = new Person("", 42);
    p2.Name = "Wallace";
    p2.Age = 75;
    
    if (p2.Equals(p1))
        Console.WriteLine("p2 and p1 have the same values.");
    
    // Output: p2 and p1 have the same values.
    

    A implementaçãoSystem.ValueType de Equals usa conversão boxing e reflexão em alguns casos. Para obter informações sobre como fornecer um algoritmo de igualdade eficiente específico ao seu tipo, consulte Como definir a igualdade de valor para um tipo. Os registros são tipos de referência que usam semântica de valor para igualdade.

  • Para determinar se os valores dos campos em duas instâncias de classe são iguais, você pode usar o Equals método ou o operador == . No entanto, use-os apenas se a classe os tiver substituído ou sobrecarregado para fornecer uma definição personalizada do que "igualdade" significa para objetos desse tipo. A classe também pode implementar a IEquatable<T> interface ou a IEqualityComparer<T> interface. Ambas as interfaces fornecem métodos que podem ser usados para testar a igualdade de valor. Ao projetar suas próprias classes que substituem Equals, siga as diretrizes declaradas em Como definir a igualdade de valor para um tipo e Object.Equals(Object).

Para obter mais informações: