Propiedades (Guía de programación de C#)

Una propiedad es un miembro que proporciona un mecanismo flexible para leer, escribir o calcular el valor de un campo privado. Las propiedades se pueden usar como si fueran miembros de datos públicos, pero son métodos especiales denominados descriptores de acceso. Esta característica permite acceder fácilmente a los datos a la vez que proporciona la seguridad y la flexibilidad de los métodos.

Información general sobre propiedades

  • Las propiedades permiten que una clase exponga una manera pública de obtener y establecer valores, a la vez que se oculta el código de implementación o verificación.
  • Para devolver el valor de la propiedad se usa un descriptor de acceso de propiedad get, mientras que para asignar un nuevo valor se emplea un descriptor de acceso de propiedad set. Un descriptor de acceso de propiedad init se usa para asignar un nuevo valor solo durante la construcción del objeto. Estos descriptores de acceso pueden tener diferentes niveles de acceso. Para más información, vea Restringir la accesibilidad del descriptor de acceso.
  • La palabra clave value se usa para definir el valor que va a asignar el descriptor de acceso set o init.
  • Las propiedades pueden ser de lectura y escritura (en ambos casos tienen un descriptor de acceso get y set), de solo lectura (tienen un descriptor de acceso get, pero no set) o de solo escritura (tienen un descriptor de acceso set, pero no get). Las propiedades de solo escritura son poco frecuentes y se suelen usar para restringir el acceso a datos confidenciales.
  • Las propiedades simples que no necesitan ningún código de descriptor de acceso personalizado se pueden implementar como definiciones de cuerpos de expresión o como propiedades implementadas automáticamente.

Propiedades con campos de respaldo

Un patrón básico para implementar una propiedad conlleva el uso de un campo de respaldo privado para establecer y recuperar el valor de la propiedad. El descriptor de acceso get devuelve el valor del campo privado y el descriptor de acceso set puede realizar alguna validación de datos antes de asignar un valor al campo privado. Ambos descriptores de acceso además pueden realizar algún cálculo o conversión en los datos antes de que se almacenen o se devuelvan.

En el ejemplo siguiente se muestra este patrón. En este ejemplo, la clase TimePeriod representa un intervalo de tiempo. Internamente, la clase almacena el intervalo de tiempo en segundos en un campo privado denominado _seconds. Una propiedad de lectura y escritura denominada Hours permite al cliente especificar el intervalo de tiempo en horas. Los descriptores de acceso get y set realizan la conversión necesaria entre horas y segundos. Además, el descriptor de acceso set valida los datos e inicia una excepción ArgumentOutOfRangeException si el número de horas no es válido.

public class TimePeriod
{
    private double _seconds;

    public double Hours
    {
        get { return _seconds / 3600; }
        set
        {
            if (value < 0 || value > 24)
                throw new ArgumentOutOfRangeException(nameof(value),
                      "The valid range is between 0 and 24.");

            _seconds = value * 3600;
        }
    }
}

Puede acceder a las propiedades para obtener y establecer el valor como se muestra en el ejemplo siguiente:

TimePeriod t = new TimePeriod();
// The property assignment causes the 'set' accessor to be called.
t.Hours = 24;

// Retrieving the property causes the 'get' accessor to be called.
Console.WriteLine($"Time in hours: {t.Hours}");
// The example displays the following output:
//    Time in hours: 24

Definiciones de cuerpos de expresión

Los descriptores de acceso de propiedad suelen constar de instrucciones de una sola línea que simplemente asignan o devuelven el resultado de una expresión. Puede implementar estas propiedades como miembros con forma de expresión. Las definiciones de cuerpos de expresión constan del símbolo => seguido de la expresión que se va a asignar a la propiedad o a recuperar de ella.

Las propiedades de solo lectura pueden implementar el descriptor de acceso get como miembro con forma de expresión. En este caso, no se usan ni la palabra clave del descriptor de acceso get ni la palabra clave return. En el ejemplo siguiente se implementa la propiedad de solo lectura Name como miembro con forma de expresión.

public class Person
{
    private string _firstName;
    private string _lastName;

    public Person(string first, string last)
    {
        _firstName = first;
        _lastName = last;
    }

    public string Name => $"{_firstName} {_lastName}";
}

Tanto el descriptor de acceso get como set se pueden implementar como miembros con forma de expresión. En este caso, las palabras clave get y set deben estar presentes. En el ejemplo siguiente se muestra el uso de definiciones de cuerpos de expresión para ambos descriptores de acceso. La palabra clave return no se usa con el descriptor de acceso get.

public class SaleItem
{
    string _name;
    decimal _cost;

    public SaleItem(string name, decimal cost)
    {
        _name = name;
        _cost = cost;
    }

    public string Name
    {
        get => _name;
        set => _name = value;
    }

    public decimal Price
    {
        get => _cost;
        set => _cost = value;
    }
}

Propiedades implementadas automáticamente

En algunos casos, los descriptores de acceso de propiedad get y set simplemente asignan un valor a un campo de respaldo o recuperan un valor de él sin incluir ninguna lógica adicional. Mediante las propiedades implementadas automáticamente, puede simplificar el código y conseguir que el compilador de C# le proporcione el campo de respaldo de forma transparente.

Si una propiedad tiene los descriptores de acceso get y set (o get y init), ambos se deben implementar de forma automática. Una propiedad implementada automáticamente se define mediante las palabras clave get y set sin proporcionar ninguna implementación. El ejemplo siguiente repite el anterior, salvo que Name y Price son propiedades implementadas automáticamente. En el ejemplo también se quita el constructor parametrizado, por lo que los objetos SaleItem ahora se inicializan con una llamada al constructor sin parámetros y un inicializador de objeto.

public class SaleItem
{
    public string Name
    { get; set; }

    public decimal Price
    { get; set; }
}

Las propiedades implementadas automáticamente pueden declarar diferentes accesibilidades para los descriptores de acceso get y set. Normalmente, declara un descriptor de acceso público get y un descriptor de acceso privado set. Puede obtener más información en el artículo sobre Restringir la accesibilidad del descriptor de acceso.

Propiedades obligatorias

A partir de C# 11, puede agregar el miembro required para forzar que el código de cliente inicialice cualquier propiedad o campo:

public class SaleItem
{
    public required string Name
    { get; set; }

    public required decimal Price
    { get; set; }
}

Para crear SaleItem, debe establecer las propiedades Name y Price mediante inicializadores de objeto, como se muestra en el código siguiente:

var item = new SaleItem { Name = "Shoes", Price = 19.95m };
Console.WriteLine($"{item.Name}: sells for {item.Price:C2}");

Especificación del lenguaje C#

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

Consulte también