Objetos (Guía de programación de C#)
Una definición de clase o struct es como un plano que especifica qué puede hacer el tipo. Un objeto es básicamente un bloque de memoria que se ha asignado y configurado en función del plano. 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 cliente es el código que utiliza estas variables para llamar a los métodos y obtener acceso a las propiedades públicas del objeto. En un lenguaje orientado a objetos como C#, un programa típico se compone de varios objetos que interactúan dinámicamente.
Nota
Los tipos estáticos se comportan de manera diferente a la que se describe aquí. Para obtener más información, vea Clases estáticas y sus miembros (Guía de programación de C#).
Instancias de struct frente aInstancias 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 un segundo objeto del mismo tipo se asigna al primer objeto, ambas variables hacen referencia al objeto en esa dirección. Este punto se analiza con más detalle más adelante, en este mismo tema.
Las instancias de clases se crean utilizando el operador new. En el ejemplo siguiente, Person es el tipo y person1 y person 2 son instancias, u objetos, de ese tipo.
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);
// Keep the console open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/*
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 de struct contiene una copia de todo el objeto. También se pueden crear instancias de structs utilizando el operador new, pero no es obligatorio, como se muestra en el ejemplo siguiente:
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);
// Keep the console open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/*
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. Ésta es una razón por la que los structs se copian en la asignación. Por el contrario, Common Language Runtime reclama automáticamente (mediante la recolección de elementos no utilizados) la memoria asignada a una instancia de clase cuando todas las referencias al objeto han quedado fuera del ámbito. No es posible destruir de manera determinista un objeto de clase como se hace en C++. Para obtener más información sobre la recolección de elementos no utilizados en .NET Framework, 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 existe una diferencia significativa de costo de rendimiento entre asignar una instancia de clase en el montón frente a asignar una instancia de struct en la pila.
Identidad de objetos frente aIgualdad de valores
Al comparar dos objetos para comprobar si son iguales, primero debe diferenciar si desea conocer si las dos variables representan al mismo objeto en memoria o si los valores de uno o más de sus campos son equivalentes. Si desea comparar valores, debe considerar 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 memoria (lo que significa que tienen la misma identidad), utilice el método estático Equals. (System.Object es la clase base implícita para todos los tipos de valor y de referencia, incluyendo las clases y structs definidos por el usuario.)
Para determinar si los campos de instancia de dos instancias de struct tienen los mismos valores, utilice el método ValueType.Equals. Dado que todas los structs heredan implícitamente de System.ValueType, se llama al método directamente en el objeto como se muestra en el ejemplo siguiente:
Person p1 = new Person("Wallace", 75);
Person p2;
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.
La implementación System.ValueType de Equals utiliza la reflexión porque debe ser capaz de determinar qué son los campos en cualquier struct. Al crear sus propios structs, invalide el método Equals para proporcionar un algoritmo de igualdad eficaz específico de su tipo.
- Para determinar si los valores de los campos de dos instancias de clase son iguales, puede usar el método Equals o el operador ==. Sin embargo, se deben utilizar 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 las interfaces IEquatable<T> o IEqualityComparer<T>. Ambas interfaces proporcionan métodos que se pueden utilizar para probar si sus valores son iguales. Al diseñar sus propias clases que invaliden Equals, asegúrese de seguir las directrices indicadas en Cómo: Definir la igualdad de valores para un tipo (Guía de programación de C#) y Object.Equals(Object).
Secciones relacionadas
Para obtener más información:
Vea también
Referencia
Herencia (Guía de programación de C#)
new (Operador, Referencia de C#)