2017-04-11 1 views
3

Comment parcourir des éléments dans un Tuple, quand je ne sais pas au moment de la compilation quels sont les types dont le tuple est composé? J'ai juste besoin d'un IEnumerable d'objets (pour la sérialisation).comment itérer sur des éléments de tuple

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; 
    } 
} 
+0

ce qui vous émettez –

+0

'valeurs var = tuple.GetType(). GetProperties(). Sélectionnez (property => property.GetValue (tuple))' – Fabio

Répondre

2

vous pouvez accéder aux propriétés et leurs valeurs par réflexion avec Type.GetProperties

var values = tuple.GetType().GetProperties().Select(property => property.GetValue(tuple)); 

Ainsi, votre méthode sera très simple requête Linq

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)); 
} 
3

Un problème ici est que vous devez traiter plusieurs types Tuple: (. Je suppose que vous voulez que cela fonctionne avec tuples avec un nombre arbitraire d'éléments) Tuple<T1, T2>, Tuple<T1, T2, T3> etc.

Une façon un peu hacky de le faire pour voir si le nom du type commence par 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 vous ne souhaitez pas le hackyness de FullName.StartsWith(...) vous pouvez le rendre plus typesafe comme ceci:

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; 
    } 
} 
0

votre code ne fonctionne pas comme prévu parce que vous attendez une correspondance exacte de Tuple<object,object> lorsque vous utilisez comme Tuple qui n'est pas le cas

Vous pouvez essayer ce qui suit pour être plus générique (si vous vous attendez toujours deux articles)

class Program 
    { 
     static void Main(string[] args) 
     { 
      Tuple<string, string> tuples = new Tuple<string, string>("test","test"); 
      foreach (string item in TupleToEnumerable<string>(tuples)) 
      { 
       Console.WriteLine(item); 

      } 
     } 

     private static IEnumerable<T> TupleToEnumerable<T>(object tuple) 
     { 
      Type t = tuple.GetType(); 
      if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Tuple<,>)) 
      { 
       var x = tuple as Tuple<T, T>; 
       yield return x.Item1; 
       yield return x.Item2; 
      } 
     } 
    } 
+0

TupleToEnumerable <_string_> (tuples) - je ne peux pas l'utiliser comme ça. Je ne sais pas à la compilation quels sont les types. –

+0

vous devez utiliser la réflexion mais au coût de la performance –

+1

Cela nécessite que les deux propriétés aient le même type, ce qui n'est pas toujours le cas. –