Objetos - criar instâncias de tipos

Uma definição de classe ou struct é como um esquema 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 projeto. 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. 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.

Nota

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

Struct Instances vs. Class Instances

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 referem ao objeto nesse endereço. Este ponto é discutido mais detalhadamente mais adiante neste artigo.

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 = {0} Age = {1}", person1.Name, 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 = {0} Age = {1}", person2.Name, person2.Age);
        Console.WriteLine("person1 Name = {0} Age = {1}", person1.Name, person1.Age);
    }
}
/*
    Output:
    person1 Name = Leopold Age = 6
    person2 Name = Molly Age = 16
    person1 Name = Molly Age = 16
*/

Como structs são tipos de valor, uma variável de um objeto struct contém uma cópia do objeto inteiro. Instâncias de structs também podem ser criadas usando o new operador, mas isso não é necessário, como 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 = {0} Age = {1}", p1.Name, 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 = {0} Age = {1}", p2.Name, p2.Age);

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

A memória para ambos p1 e p2 é alocada na pilha de threads. Essa memória é recuperada juntamente com o tipo ou método em que é declarada. Esta é uma das razões pelas quais as estruturas são copiadas na atribuição. Por outro lado, a memória alocada para uma instância de classe é recuperada automaticamente (lixo coletado) pelo common language runtime quando todas as referências ao objeto saíram do escopo. Não é possível destruir deterministicamente um objeto de classe como em C++. Para obter mais informações sobre a coleta de lixo no .NET, consulte Coleta de lixo.

Nota

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

Identidade do objeto vs. igualdade de valor

Ao comparar dois objetos para igualdade, você deve primeiro 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 estruturas e classes definidas pelo usuário.)

  • Para determinar se os campos de instância em duas instâncias struct têm os mesmos valores, use o ValueType.Equals método. Como todas as estruturas herdam implicitamente do 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 System.ValueType implementação de Equals usos boxe e reflexão em alguns casos. Para obter informações sobre como fornecer um algoritmo de igualdade eficiente específico para o seu tipo, consulte Como definir 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ê poderá 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 valores. Ao projetar suas próprias classes que substituem Equals, certifique-se de seguir as diretrizes indicadas em Como definir igualdade de valor para um tipo e Object.Equals(Object).

Para mais informações: