How to iterate over the elements of a tuple
How can I iterate over the elements in a tuple when I don't know at compile time what are the types that the tuple consists of? I just need IEnumerable objects (for serialization).
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;
}
}
source to share
You can access properties and their values by reflection with Type.GetProperties
var values = tuple.GetType().GetProperties().Select(property => property.GetValue(tuple));
This way your method will be very simple. Linq query
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));
}
source to share
The problem is that you have to deal with several types Tuple
: Tuple<T1, T2>
, Tuple<T1, T2, T3>
etc. (I'm assuming you want this to work for tuples with an arbitrary number of elements.)
A somewhat hacky way to do this is to find out if a type name begins with 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);
}
}
}
If you don't like hacking FullName.StartsWith(...)
, you can make it more typical:
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;
}
}
source to share
your code doesn't work as expected because you expect an exact match Tuple<object,object>
when used as a Tuple, which is not the case.
You can try the following more general one (if you always expect two items)
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;
}
}
}
source to share