Compartir a través de


Objetos: creación de instancias de tipos

Una definición de clase o estructura es como un plano técnico que especifica lo que puede hacer el tipo. Un objeto es básicamente un bloque de memoria que se ha asignado y configurado según el plano técnico. Un programa puede crear muchos objetos de la misma clase. Los objetos también se denominan instancias y se pueden almacenar en una variable con nombre o en una matriz o colección. El código de cliente es el código que usa estas variables para llamar a los métodos y acceder a las propiedades públicas del objeto. En un lenguaje orientado a objetos como C#, un programa típico consta de varios objetos que interactúan dinámicamente.

Nota:

Los tipos estáticos se comportan de forma diferente a lo que se describe aquí. Para obtener más información, vea Clases estáticas y miembros de clase estática.

Instancias de estructura frente a instancias de clase

Dado que las clases son tipos de referencia, una variable de un objeto de clase contiene una referencia a la dirección del objeto en el montón administrado. Si se asigna una segunda variable del mismo tipo a la primera variable, ambas variables hacen referencia al objeto en esa dirección. Este punto se describe con más detalle más adelante en este artículo.

Las instancias de clases se crean mediante el new operador . En el ejemplo siguiente, Person es el tipo y person1 y person2 son instancias, o objetos, de ese 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
*/

Dado que los structs son tipos de valor, una variable de un objeto struct contiene una copia de todo el objeto. Las instancias de structs también se pueden crear mediante el new operador , pero esto no es necesario, como se muestra en el ejemplo siguiente:

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
    */
}

La memoria para p1 y p2 se asigna en la pila de subprocesos. Esta memoria se reclama junto con el tipo o método en el que se declara. Este es uno de los motivos por los que se copian las estructuras en la asignación. Por el contrario, la memoria que se asigna a una instancia de clase la reclama automáticamente (recolección de elementos no utilizados) Common Language Runtime cuando todas las referencias al objeto se han salido del ámbito. No es posible destruir de forma determinista un objeto de clase como puede en C++. Para obtener más información sobre la recolección de elementos no utilizados en .NET, vea Recolección de elementos no utilizados.

Nota:

La asignación y desasignación de memoria en el montón administrado están muy optimizadas en Common Language Runtime. En la mayoría de los casos, no hay ninguna diferencia significativa en el costo de rendimiento de asignar una instancia de clase en el montón frente a asignar una instancia de estructura en la pila.

Identidad de objeto frente a igualdad de valores

Al comparar dos objetos para obtener igualdad, primero debe distinguir si desea saber si las dos variables representan el mismo objeto en la memoria o si los valores de uno o varios de sus campos son equivalentes. Si piensa comparar valores, debe tener en cuenta si los objetos son instancias de tipos de valor (structs) o tipos de referencia (clases, delegados, matrices).

  • Para determinar si dos instancias de clase hacen referencia a la misma ubicación en la memoria (lo que significa que tienen la misma identidad), use el método estático Object.Equals . (System.Object es la clase base implícita para todos los tipos de valor y tipos de referencia, incluidas las estructuras y clases definidas por el usuario).

  • Para determinar si los campos de instancia de dos instancias de estructura tienen los mismos valores, use el ValueType.Equals método . Dado que todas las estructuras heredan implícitamente de System.ValueType, llame al método directamente en el objeto como se muestra en el ejemplo siguiente:

    // 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.
    

    En algunos casos, la implementación de System.ValueType de Equals utiliza la conversión boxing y la reflexión. Para obtener información sobre cómo proporcionar un algoritmo de igualdad eficaz específico del tipo, vea Cómo definir la igualdad de valores para un tipo. Los registros son tipos de referencia que usan la semántica de valores para la igualdad.

  • Para determinar si los valores de los campos de dos instancias de clase son iguales, es posible que pueda usar el Equals método o el operador == . En cambio, úselos solo si la clase los ha invalidado o sobrecargado para proporcionar una definición personalizada de lo que significa "igualdad" para los objetos de ese tipo. La clase también puede implementar la IEquatable<T> interfaz o la IEqualityComparer<T> interfaz . Ambas interfaces proporcionan métodos que se pueden usar para probar la igualdad de valores. Al diseñar sus propias clases que invalidan Equals, asegúrese de seguir las instrucciones indicadas en Cómo definir la igualdad de valores para un tipo y Object.Equals(Object).

Para obtener más información: