Search code examples
c#reflectioncasting

How to cast from object to type which uses generics in C#


My method receives an object. I determine it is a 2 dimension Tuple Tuple<,> using reflection. I don't know the generic types of the 2 dimensional tuple at compile time. How can I access the fields from the tuple? I assume I must cast to the underlying tuple type, but I can't see how.

public static class Foo
{
    private static Bar(object inputObject, Type inputType)
    {
        if (inputType.IsOrImplementsType(typeof(Tuple<,>)))
        {
            Type keyType = inputType.GenericTypeArguments[0];
            Type valueType = inputType.GenericTypeArguments[1];                
            // Now how can I cast to the concrete type of Tuple<keyType, valueType> to access the tuple Item1 and Item2 fields?
            // Doing this yields : keyType is a variable but is used like a type.
            var convertedTuple = inputObject as Tuple<keyType, valueType>;
            // now we can access convertedTuple.Item1
        }
    }
}

Solution

    • You don't need to use System.Reflection here: just the is operator.
    • You can use the System.Runtime.CompilerServices.ITuple interface.
    • interface ITuple is implemented by both class Tuple<...> and struct ValueTuple<...>, which is nice, as it means you can have a single code-path.
    private static void Bar( object? inputObject )
    {
        if( inputObject is ITuple tuple && tuple.Length == 2 )
        {
            Object? value0 = tuple[0];
            Object? value1 = tuple[1];
    
            // Do stuff here...
        }
    }
    

    ...but if you know inputObject is always going to be a Tuple type, then why not do this?

    // For System.Tuple<T0,T1>:
    private static void Bar<T0,T1>( Tuple<T0,T1> inputObject )
    {
        T0 value0 = inputObject.Item1;
        T1 value1 = inputObject.Item2;
    
        // Do stuff here...
    }
    
    // For System.ValueTuple<T0,T1>:
    private static void Bar<T0,T1>( ValueTuple<T0,T1> inputObject )
    {
        T0 value0 = inputObject.Item1;
        T1 value1 = inputObject.Item2;
    
        // Do stuff here...
    }