
Los records son una interesante fórmula para definir tipos en C# de forma rápida gracias a su concisa sintaxis, además de ofrecer otras ventajas, entre las que destacan la inmutabilidad o la implementación automática de métodos como Equals()
, GetHashCode()
o ToString()
.
Por si no tenéis esto muy fresco, aquí va un ejemplo de record y la clase tradicional equivalente en C#:
// Record:
public record Person(string FirstName, string LastName);
// Clase equivalente (generada automáticamente):
public class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public override bool Equals(object obj)
{
return obj is Person person &&
FirstName == person.FirstName &&
LastName == person.LastName;
}
public override int GetHashCode()
{
return HashCode.Combine(FirstName, LastName);
}
public Person With(string FirstName = null, string LastName = null)
{
return new Person(FirstName ?? this.FirstName, LastName ?? this.LastName);
}
public void Deconstruct(out string firstName, out string lastName)
{
firstName = this.FirstName;
lastName = this.LastName;
}
}
Como podéis comprobar, hay pocas características de C# que ofrezcan una relación código/funcionalidad tan bárbara como los records. Por ello, poco a poco van ganando popularidad y comenzamos a verlos ya de forma habitual en código propio y ajeno.
Sin embargo, su concisa sintaxis hacen que a veces no sea fácil intuir cómo resolver algunos escenarios que, usando las clases tradicionales, serían triviales.
Por ejemplo, hoy vamos a centrarnos en un escenario muy concreto pero frecuente, cuya solución seguro que veis que puede ser aplicada en otros casos: ya que en los records no definimos propiedades de forma explícita, ¿cómo podríamos aplicarles atributos?
Por ejemplo, en el siguiente código definimos un record, creamos una instancia del mismo y mostramos su serialización en JSON por consola:
var p = new Person("John Smith", "jsmith@server.com");
Console.WriteLine(JsonSerializer.Serialize(p));
// Muestra: {"Name":"John Smith","Email":"jsmith@server.com"}
public record Person(string Name, string Email);
Pero imaginad que queremos ignorar la propiedad Email
y que la propiedad Name
aparezca como fullName
. Normalmente usaríamos atributos como [JsonIgnore]
o [JsonPropertyName("fullName")]
sobre las propiedades para conseguirlo, pero como en este caso no las tenemos disponibles, debemos hacerlo así:
public record Person([property: JsonPropertyName("fullName")] string Name,
[property: JsonIgnore] string Email);
Observad que no se trata de aplicar directamente los atributos [JsonIgnore]
, porque entonces los estaríamos usando contra los parámetros del constructor del record. Debemos incluir el prefijo property:
para indicar que los atributos deben ser aplicados a las propiedades generadas automáticamente a partir de ellos.
De esta forma, si volvemos a ejecutar el código, veremos que ahora la propiedad Email
no aparece en la serialización y la propiedad Name
aparece como fullName
:
var p = new Person("John Smith", "jsmith@server.com");
Console.WriteLine(JsonSerializer.Serialize(p));
// Muestra: {"fullName":"John Smith"}
public record Person([property: JsonPropertyName("fullName")] string Name,
[property: JsonIgnore] string Email);
Como decía más arriba, aunque el ejemplo hayamos visto cómo aplicar atributos de serialización o deserialización, en realidad podríamos hacer lo mismo con cualquier otro tipo de atributo que en condiciones normales aplicaríamos a las propiedades de una clase.
¡Espero que os sea de utilidad! 😊
Publicado en: www.variablenotfound.com.
Aún no hay comentarios, ¡sé el primero!
Enviar un nuevo comentario