C# – Cómo deconstruir un objeto

C# – Cómo deconstruir un objeto

Deconstruir un objeto significa asignar sus propiedades a varias variables con una sola línea usando asignación de deconstrucción sintaxis (también conocida como desestructuración o desempaquetado). Para poder deconstruir un objeto, necesita tener un método Deconstruct(). Algunos tipos incorporados tienen esto (tuplas, pares de clave/valor de diccionario, registros) y puede agregarlo a otros tipos.

Aquí hay un ejemplo de deconstrucción de un objeto de clase:

var coder = new Coder()
{
    Name = "Bob",
    Language = "C#",
    YearsExperience = 5
};

var (name, lang) = coder;

Console.WriteLine($"{name} is a {lang} coder");
Code language: C# (cs)

Esto genera:

Bob is a C# coderCode language: plaintext (plaintext)

La clase Coder tiene el método Deconstruct() requerido (parámetros void + out):

public class Coder
{
    public string Name { get; set; }
    public string Language { get; set; }
    public int YearsExperience { get; set; }

    public void Deconstruct(out string name, out string language)
    {
        name = Name;
        language = Language;
    }
}
Code language: C# (cs)

Tenga en cuenta que no necesita mostrar todas las propiedades. Solo los que elijas.

Cuando usa la sintaxis de asignación de deconstrucción en un objeto, en realidad solo llama a su método Deconstruct(). Esto es azúcar de sintaxis y se basa puramente en la convención.

En este artículo, mostraré algunos ejemplos más de deconstrucción.

Nota:un tipo puede tener varios métodos Deconstruct() sobrecargados. Esto le permite usar el correcto. Si tiene que usar un deconstructor con propiedades no deseadas, deséchelo con _.

Deconstruir una tupla

La deconstrucción de tuplas es el escenario más común para la deconstrucción. Este es uno de los ejemplos del uso de la deconstrucción de tuplas.

Dividir una cadena le brinda una matriz de cadenas, a las que puede acceder por índice. Esto puede ser propenso a errores y no es muy útil usar "arr[1]" por todas partes. Una idea es poner los valores divididos en una tupla y luego deconstruir la tupla en variables con nombre. He aquí un ejemplo:

var fields = "Bob,C#,5".Split(",");
var (name, lang, years) = (fields[0], fields[1], fields[2]);

Console.WriteLine($"{name} has used {lang} for {years} years");
Code language: C# (cs)

Esto genera lo siguiente:

Bob has used C# for 5 yearsCode language: plaintext (plaintext)

Podría estar pensando, ¿no podría simplemente poner tres líneas de código para asignar a estas variables? Sí, podrías, pero recuerda que la deconstrucción es azúcar de sintaxis y se trata de reducir esto a una sola línea.

Deconstruir los pares clave/valor de un diccionario

El tipo de par clave/valor del diccionario implementa Deconstruct(), por lo que se pueden deconstruir en variables de clave y valor bien nombradas. He aquí un ejemplo:

var wordCountMap = new Dictionary<string, int>()
{
    ["apple"] = 10,
    ["dog"] = 5,
    ["fish"] = 6
};

foreach(var (word, count) in wordCountMap)
{
    Console.WriteLine($"{word} appeared {count} times");
}
Code language: C# (cs)

Esto genera lo siguiente:

apple appeared 10 times
dog appeared 5 times
fish appeared 6 timesCode language: plaintext (plaintext)

Esto es mejor que usar una variable de bucle KeyValuePair (por ejemplo, kvp.Key y kvp.Value).

Añadir Deconstruct() como método de extensión

Cuando desee poder usar la deconstrucción en un tipo que no tiene Deconstruct() implementado, y no puede cambiar directamente el tipo (de terceros o integrado), puede agregar Deconstruct() como una extensión método para el tipo.

Por ejemplo, supongamos que está utilizando la siguiente clase Coder de una biblioteca de terceros:

public class Coder
{
    public string Name { get; set; }
    public string Language { get; set; }
    public int YearsExperience { get; set; }
}
Code language: C# (cs)

Intenta deconstruir un objeto Coder, pero recibe un montón de errores de compilación porque no tiene un método Deconstruct():

//CS1061 - 'Coder' does not contain a definition for 'Deconstruct'... (and 3 other errors)
var (name, lang) = coder;
Code language: C# (cs)

No puede modificar directamente la clase Coder (de terceros), pero puede implementar Deconstruct() como un método de extensión:

public static class CoderExtensions
{
    public static void Deconstruct(this Coder coder, out string name, out string language)
    {
        name = coder.Name;
        language = coder.Language;
    }
}
Code language: C# (cs)

Ahora puede deconstruir el objeto Coder.

Un tipo puede tener múltiples implementaciones de Deconstruct(). Entonces, incluso si una clase ya tiene un método Deconstruct(), puede agregar su propio método de extensión para obtener exactamente las propiedades que desea.