Sobre la implementación interna de las tuplas-valor (y 4)

“When the hills of Los Angeles are burning
Palm trees are candles in the murder wind
So many lives are on the breeze
Even the stars are ill at ease
And Los Angeles is burning…”
Bad Religion, Los Angeles is Burning (2004)

Parte 1
Parte 2
Parte 3

Para concluir la serie sobre la implementación interna de las tuplas-valor, hoy presento un pequeño divertimento que vuelve a incidir sobre los detalles de dicha implementación.

Suponga que tiene una tupla-valor con varios elementos, y quiere tratar a dichos elementos como una secuencia, por ejemplo para agregarlos de alguna manera (recuerde que el operador Aggregate de LINQ no está limitado, ni mucho menos,  a secuencias numéricas). Independientemente de que LINQ ya hace tiempo que dejó estar en el centro de atención para convertirse en algo “normal”, estamos en presencia de un caso típico en el que quisiéramos “habilitar para LINQ” un tipo de datos específico, para lo que tan solo hace falta crear un método extensor que reciba una instancia del tipo y produzca a partir de ella un IEnumerable o IEnumerable<T> a recorrer. Es un tema al que dediqué varios artículos en la pasada década, en particular éste. Con un método como el anterior (al que llamaremos, como se recomienda, AsEnumerable), podremos hacer cosas como lo siguiente:

using System;
using System.Linq;
 
namespace ValueTuples
{
    class MainClass
    {
        static void Main()
        {
            var tuple = (12345678910);
            var sum = (from int x in tuple.AsEnumerable()
                       where x % 2 == 0
                       select x).Sum();              
            Console.WriteLine(sum); // Imprime 30
        }
    }
}

La implementación del método extensor que se me ha ocurrido (teniendo en cuenta las cosas que hemos venido hablando sobre la implementación interna de las tuplas-valor) es la que sigue a continuación; se aceptan sugerencias para su mejora.

using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using SC = System.StringComparison;
 
namespace ValueTuples
{
    public static class ValueTupleExtensions
    {
        public static IEnumerable AsEnumerable(this object valueTuple)
        {
            Type type = valueTuple.GetType();
            if (!type.FullName.StartsWith("System.ValueTuple"                                          SC.InvariantCulture))
                throw new InvalidOperationException("Invalid type");
            foreach (FieldInfo fi in type.GetFields().OrderBy(fi => fi.Name))
            {
                if (fi.Name == "Rest"// "El octavo pasajero"
                {
                    foreach (object o in AsEnumerable(fi.GetValue(valueTuple)))
                        yield return o;
                }
                else
                {
                    yield return fi.GetValue(valueTuple);
                }
            }
        }
    }
}

Referencia musical: Como el tiempo para concebir y escribir este post se presentó debido a un incendio forestal que amenazó nuestra empresa hoy hasta el punto de que nos evacuaron a casa, lo menos que pude hacer fue buscar una canción alusiva al tema, y creo que encontré una bastante buena. Bad Religion es una banda de punk-rock formada en Los Ángeles en 1980 (ya yo me estaba haciendo viejo por esa época) y que aún se mantiene activa. No soy un experto en su obra, pero suenan bien y tienen letras inteligentes.

Octavio Hernandez

Desarrollador y consultor en tecnologías .NET. Microsoft C# MVP entre 2004 y 2010.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *