Introducción a las clases

Tipos de referencia

Un tipo que se define como una class, es un tipo de referencia. Al declarar una variable de un tipo de referencia en tiempo de ejecución, esta contendrá el valor null hasta que se cree expresamente una instancia de la clase mediante el operador new o se le asigne un objeto de un tipo compatible que se ha creado en otro lugar, tal y como se muestra en el ejemplo siguiente:

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

Cuando se crea el objeto, se asigna suficiente memoria en el montón administrado para ese objeto específico y la variable solo contiene una referencia a la ubicación de dicho objeto. La memoria que un objeto usa la reclama la funcionalidad de administración automática de memoria de CLR, lo que se conoce como recolección de elementos no utilizados. Para obtener más información sobre la recolección de elementos no utilizados, vea Administración automática de la memoria y recolección de elementos no utilizados.

Declarar clases

Las clases se declaran mediante la palabra clave class seguida por un identificador único, como se muestra en el siguiente ejemplo:

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

Un modificador de acceso opcional precede a la palabra clave class. Como en este caso se usa public, cualquier usuario puede crear instancias de esta clase. El nombre de la clase sigue a la palabra clave class. El nombre de la clase debe ser un nombre de identificador de C# válido. El resto de la definición es el cuerpo de la clase, donde se definen los datos y el comportamiento. Los campos, las propiedades, los métodos y los eventos de una clase se denominan de manera colectiva miembros de clase.

Creación de objetos

Aunque a veces se usan indistintamente, una clase y un objeto son cosas diferentes. Una clase define un tipo de objeto, pero no es un objeto en sí. Un objeto es una entidad concreta basada en una clase y, a veces, se conoce como una instancia de una clase.

Se pueden crear objetos usando la palabra clave new seguida del nombre de la clase, como en este ejemplo:

Customer object1 = new Customer();

Cuando se crea una instancia de una clase, se vuelve a pasar al programador una referencia al objeto. En el ejemplo anterior, object1 es una referencia a un objeto que se basa en Customer. Esta referencia apunta al objeto nuevo, pero no contiene los datos del objeto. De hecho, puede crear una referencia de objeto sin tener que crear ningún objeto:

Customer object2;

No se recomienda crear referencias de objeto que no remitan a ningún objeto, ya que, si se intenta obtener acceso a un objeto a través de este tipo de referencia, se producirá un error en tiempo de ejecución. Este tipo de referencia se puede haber creado para hacer referencia a un objeto, ya sea creando uno o asignándola a un objeto existente, como en el ejemplo siguiente:

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

Este código crea dos referencias de objeto que hacen referencia al mismo objeto. Por lo tanto, los cambios efectuados en el objeto mediante object3 se reflejan en los usos posteriores de object4. Dado que los objetos basados en clases se tratan por referencia, las clases se denominan "tipos de referencia".

Constructores e inicialización

En las secciones anteriores presentamos la sintaxis para declarar un tipo de clase y crear una instancia de ese tipo. Al crear una instancia de un tipo, conviene asegurarse de que sus campos y propiedades se inicializan con valores útiles. Hay varias maneras de inicializar valores:

  • Aceptando los valores predeterminados
  • Con inicializadores de campo
  • Con parámetros del constructor
  • Inicializadores de objeto

Cada tipo de .NET tiene un valor predeterminado, que suele ser 0 en los tipos de número y null en todos los tipos de referencia. Puede basarse en ese valor predeterminado si tiene sentido en su aplicación.

Cuando el valor predeterminado de .NET no es el valor correcto, puede establecer un valor inicial usando un inicializador de campo:

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

Para requerir que los autores de llamadas proporcionen un valor inicial, defina un constructor que se encargue de establecer ese valor inicial:

public class Container
{
    private int _capacity;

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

A partir de C# 12, puede definir un constructor principal como parte de la declaración de clase:

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

Agregar parámetros al nombre de clase define el constructor principal. Esos parámetros están disponibles en el cuerpo de la clase, que incluye sus miembros. Puede usarlos para inicializar campos o en cualquier otro lugar donde los necesite.

También puede usar el modificador required en una propiedad y permitir que los autores de llamadas usen un inicializador de objeto para establecer el valor inicial de la propiedad:

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

Agregar las palabras clave required obliga a los llamadores a establecer esas propiedades como parte de una expresión new:

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

Herencia de clases

Las clases admiten completamente la herencia, una característica fundamental de la programación orientada a objetos. Al crear una clase, puede heredar de cualquier otra clase que no esté definida como sealed. Otras clases pueden heredar de la clase e invalidar los métodos virtuales de clase. Además, puede implementar una o varias interfaces.

La herencia se consigue mediante una derivación, en la que se declara una clase mediante una clase base, desde la que hereda los datos y el comportamiento. Una clase base se especifica anexando dos puntos y el nombre de la clase base seguido del nombre de la clase derivada, como en el siguiente ejemplo:

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

Cuando una declaración de clase incluye una clase base, hereda todos los miembros de la clase base, excepto los constructores. Para obtener más información, vea Herencia.

Una clase de C# solo puede heredar directamente de una clase base. En cambio, dado que una clase base puede heredar de otra clase, una clase puede heredar indirectamente varias clases base. Además, una clase puede implementar directamente una o varias interfaces. Para obtener más información, vea Interfaces.

Una clase se puede declarar como abstract. Una clase abstracta contiene métodos abstractos que tienen una definición de firma, pero no tienen ninguna implementación. No se pueden crear instancias de las clases abstractas. Solo se pueden usar a través de las clases derivadas que implementan los métodos abstractos. En cambio, una clase sellada no permite que otras clases se deriven de ella. Para más información, vea Clases y miembros de clase abstractos y sellados.

Las definiciones de clase se pueden dividir entre distintos archivos de código fuente. Para más información, vea Clases y métodos parciales.

Especificación del lenguaje C#

Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.