¿Cómo iterar sobre elementos en una tupla, cuando no sé en tiempo de compilación cuáles son los tipos de los que se compone la tupla? Solo necesito un IEnumerable de objetos (para serialización).
private static IEnumerable TupleToEnumerable(object tuple) { Type t = tuple.GetType(); if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Tuple<,>)) { var x = tuple as Tuple<object, object>; yield return x.Item1; yield return x.Item2; } }Puede acceder a las propiedades y sus valores por reflexión con Type.GetProperties
var values = tuple.GetType().GetProperties().Select(p => p.GetValue(tuple));Entonces su método será una consulta Linq muy simple
private static IEnumerable TupleToEnumerable(object tuple) { // You can check if type of tuple is actually Tuple return tuple.GetType() .GetProperties() .Select(property => property.GetValue(tuple)); }En .NET Core 2.0+ o .NET Framework 4.7.1+, hay
es de una interfaz ITuple interface
var data = (123, "abc", 0.983, DateTime.Now); ITuple iT = data as ITuple; for(int i=0; i<iT.Length;i++) Console.WriteLine(iT[i]);Un problema aquí es que tiene que lidiar con múltiples tipos de tuplas: Tuple Tuple<T1, T2> , Tuple<T1, T2, T3> etc. (Supongo que desea que esto funcione con tuplas con un número arbitrario de elementos .)
Una forma un tanto complicada de hacerlo es ver si el nombre del tipo comienza con System.Tuple :
public static IEnumerable TupleToEnumerable(object tuple) { Type t = tuple.GetType(); if (t.IsGenericType && t.GetGenericTypeDefinition().FullName.StartsWith("System.Tuple")) { for (int i = 1;; ++i) { var prop = t.GetProperty("Item" + i); if (prop == null) yield break; yield return prop.GetValue(tuple); } } } Si no te gusta la piratería de FullName.StartsWith(...) puedes hacerlo más seguro de tipos así:
public static IEnumerable TupleToEnumerable(object tuple) { Type t = tuple.GetType(); if (isTupleType(t)) { for (int i = 1;; ++i) { var prop = t.GetProperty("Item" + i); if (prop == null) yield break; yield return prop.GetValue(tuple); } } } private static bool isTupleType(Type type) { if (!type.IsGenericType) return false; var def = type.GetGenericTypeDefinition(); for (int i = 2;; ++i) { var tupleType = Type.GetType("System.Tuple`" + i); if (tupleType == null) return false; if (def == tupleType) return true; } }