Seguimos analizando las novedades de .NET 9, y en esta ocasión le toca el turno a la actualización en miembros de clases parciales de C# 13.
Las clases o tipos parciales de C# están con nosotros casi desde los inicios de .NET, desde los tiempos de C# 2.0. Como sabemos, éstas permiten dividir la implementación de un tipo en varios archivos. Su existencia se debía a varios motivos:
- Permitir a los desarrolladores trabajar en clases de forma concurrente sin bloquearse (recordemos que por aquellos tiempos aún pululaban por ahí infames sistemas de control de código fuente como SourceSafe).
- Trocear clases extensas para facilitar su comprensión y mantenimiento.
- Y, el que es más importante, posibilitar el uso sencillo de herramientas de generación de código que, de alguna forma, tuvieran que completar la implementación de código del usuario.
Acompañando a las clases parciales, se introdujo también el soporte para métodos parciales. Aunque su uso era limitado y podía depararnos algunas sorpresas, eran útiles para comunicar de forma segura distintos fragmentos de la clase. Básicamente, consistía en que una porción de una clase podía definir un método e invocarlo desde su código, delegando a otras porciones su implementación. Si no se implementaba en ninguna otra parte, simplemente no se generaba el código de la invocación.
Veamos un ejemplo del uso de estas características:
// Archivo: Ejemplo.Main.cs
public partial class Ejemplo
{
// El método parcial se declara sin implementación...
partial void Log(string msg);
public void RealizarAlgo()
{
hacerAlgoComplejo();
Log("¡Ojo!"); // Usamos el método
// parcial declarado antes
}
}
// Archivo: Ejemplo.Log.cs
public partial class Ejemplo
{
partial void Log(string msg)
{
Console.WriteLine(msg);
}
}
Pues bien, casi dos décadas más tarde, los tipos parciales van a recibir algunas actualizaciones interesantes en C# 13, posibilitando que, además de métodos, puedan definirse propiedades parciales.
Se trata de una característica muy demandada por la comunidad, sobre todo para facilitar la integración de código generado con herramientas automáticas como los source generators, que están tomando cada vez más relevancia.
Por ejemplo, seguro que alguna vez habéis sufrido a la hora de usar INotifyPropertyChanged
en view models, cuando queréis notificar cambios en propiedades, porque tenéis que implementar un montón de código repetitivo parecido al siguiente:
public partial class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// Este código se repite en todas las propiedades
public string UserName
{
get => _userName;
set {
if (value != _userName)
{
_userName = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(UserName)));
}
}
}
}
Usando propiedades parciales, ahora podremos tener algo así:
// UserCode.cs
public partial class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChanged]
public partial string UserName { get; set; }
}
Y con esto, un generador de código que atienda al atributo [NotifyPropertyChanged]
podría añadir la implementación completa de la propiedad parcial, como la siguiente:
// Generated.cs
public partial class ViewModel
{
private string __generated_userName;
public partial string UserName
{
get => __generated_userName;
set
{
if (value != __generated_userName)
{
__generated_userName = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(UserName)));
}
}
}
}
El uso de propiedades parciales y muy similar al que ya conocemos: se declaran en una parte de la clase y se implementan en otra, aunque hay que tener en cuenta algunos detalles.
Primero, como es obvio, que las propiedades parciales deben ser declaradas y definidas en distintas porciones de una clase parcial. Ambas deben tener el modificador partial
y el mismo nombre, y deben tener el mismo tipo de retorno y visibilidad.
Segundo, se entiende que la declaración de la propiedad parcial es aquella que, además de usar el modificador partial
, contiene únicamente su getter y/o setter, ambos sin cuerpo, como en el siguiente ejemplo:
public partial string UserName { get; set; }
La implementación de esta propiedad, por tanto, deberá contener obligatoriamente el cuerpo de los métodos getter y/o setter definidos en su declaración:
public partial string UserName
{
get
{
... // Retornar el valor
}
set
{
... // Setear el valor
}
}
Como consecuencia de esto, las propiedades parciales no pueden ser propiedades automáticas, deben tener un cuerpo que implemente su lógica de obtención y/o asignación.
Además, si la declaración define por ejemplo un getter y un setter, la implementación de la propiedad parcial debe especificar el cuerpo de ambos métodos. No se pueden implementar solo uno de ellos.
Tercero, las propiedades parciales no pueden ser definidas como abstractas, ni implementar interfaces de forma explícita.
Y finalmente, cabe citar que los atributos de la propiedad resultante será la unión de los atributos de la declaración y la implementación, sin un orden o prioridad específicos.
Publicado en Variable not found.
Aún no hay comentarios, ¡sé el primero!
Enviar un nuevo comentario