Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

18 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 17 de diciembre de 2024
Programador rupestre

A principios de siglo, con un C# aún bastante primitivo, las propiedades que almacenaban datos en una clase teníamos que definirlas siempre usando un backing field, es decir, un campo privado que almacenaba el valor, y accediendo a él mediante métodos getter y setter. Es decir, algo así:

public class Customer
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
    ...
}

Esto cambió en 2007 con la llegada de las propiedades automáticas, una maravilla para nuestros cansados dedos, que desde entonces usamos en la mayoría de ocasiones. Gracias a ellas, podemos definir una propiedad sin tener que implementar sus métodos accesores ni su campo privado correspondiente, porque el compilador se encargaba de crearlos por nosotros. De esta forma, código anterior quedaba así:

public class Customer
{
    public string Name { get; set; }
    ...
}

En realidad, se trataba sólo de un azucarillo sintáctico. Por detrás, el compilador está generando el campo privado y transformando nuestro código para utilizarlo; de hecho, el código generado de la clase anterior es algo así (algo simplificado para que se pueda leer mejor):

public class Customer
{
    private string <Name>k__BackingField;

    public string Name
    {
        get { return <Name>k__BackingField; }
        set { <Name>k__BackingField = value; }
    }
}

Aunque obviamente usar propiedades automáticas es mucho más cómodo que la opción anterior, tiene un inconveniente: no tenemos forma de acceder al campo generado por el compilador, algo que puede resultar interesante si nos interesa realizar algún tipo de validación o lógica adicional en el getter o setter más allá de simplemente devolver o asignar el valor.

Por ejemplo, imaginemos que queremos que el nombre de nuestro cliente siempre esté en mayúsculas. Con una propiedad automática, simplemente no podemos hacerlo, y tendremos que recurrir a las verbosas propiedades tradicionales con backing fields.

Y aquí es donde entran en escena las propiedades semiautomáticas...

Propiedades semiautomáticas

Las propiedades semiautomáticas son una mezcla entre las propiedades automáticas y las tradicionales con backing field, tomando lo mejor de cada una de estas opciones. Se definen de la misma forma que las automáticas, pero permiten acceder al campo privado que el compilador ha generado para ellas desde el cuerpo de los getters y setters, usando la nueva palabra clave contextual field.

De esta forma, podemos realizar operaciones adicionales, como si tuviéramos un backing field definido por nosotros, pero sin necesidad de hacerlo explícitamente. Veamos un ejemplo sencillo de uso:

public class Customer
{
    public string Name
    {
        get; 
        set => field = value.ToUpper();
    }
}

Por detrás, en tiempo de compilación, se sustituye la palabra clave field por el nombre del campo privado correspondiente en cada caso. Por ejemplo, supongamos la siguiente clase:

public class Customer
{
    public string Name { get; set => field = value.ToUpper(); }
    public string Email { get; set => field = value.ToLower(); }
}

El código generado por el compilador sería algo así:

public class Customer
{
    private string <Name>k__BackingField;
    private string <Email>k__BackingField;

    public string Name
    {
        get { return <Name>k__BackingField; }
        set { <Name>k__BackingField = value.ToUpper();}
    }

    public string Email
    {
        get { return <Email>k__BackingField; }
        set { <Email>k__BackingField = value.ToLower(); }
    }
}

Vale, pero, ¿y si ya tengo un campo que se llamaba field?

En el interior del código del getter o setter de una propiedad semiautomática, la palabra clave field siempre se refiere al campo privado que el compilador ha generado para la ella.

Por tanto, si ya tenemos un campo con ese nombre y queremos usarlo desde el getter o setter, tendremos que indicarlo expresamente usando el cualificador this, o bien escapándolo con el carácter @:

public class Customer
{
    private string field;

    public string Name
    {
        get => this.field;
        set => this.field = value.ToUpper();

        // O bien:
        // get => @field;
        // set => @field = value.ToUpper();
    }
}

Pero ojo: ¡es una característica preliminar en C# 13!

Por defecto, la palabra clave contextual field no está disponible en C# 13 (lanzado con .NET 9) porque se trata de una característica que está aún en fase preliminar.

Para habilitar su uso, hay que añadir la propiedad <LangVersion> con el valor "preview" al archivo .csproj:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        ...
        <LangVersion>preview</LangVersion>
    </PropertyGroup>
</Project>

Podemos suponer que esto no será necesario a partir de la siguiente versión del lenguaje, pero por ahora es necesario para poder usar esta característica.

¡Espero que os sea útil!

Publicado en Variable not found.

Aún no hay comentarios, ¡sé el primero!