Search code examples
c#.netreflectioncontravariance

Is there a way to discover the original generic argument type of a instance of an Action<in T> delegate?


Is there a way to find the declared generic argument type of an instance of an Action delegate?

In the following code the WriteGenericArgumentType function expects and instance of Action<String> but because Action<in T> allows for contravariance callers of the function are able to call it with Action<Object>.

static void Main( )
{
    WriteGenericArgumentType( new Action<string>( s => { } ) );
    WriteGenericArgumentType( new Action<object>( o => { } ) );
}

static void WriteGenericArgumentType( Action<string> action )
{
    Console.WriteLine( DiscoverGenericArgumentType( action ).Name );
}

static Type DiscoverGenericArgumentType( Delegate action )
{
    return action.GetType().GetGenericArguments()[0];
}

However, I need to be able to discover the generic argument type that was defined in the signature of WriteGenericArgumentType from the instance of the delegate that is passed to DiscoverGenericArgumentType.

When the code runs I get the following output:

String
Object

But I need it to be:

String
String

For my purposes I cannot change the signature of DiscoverGenericArgumentType and I need that function to return string as the type.

I know I can create my own generic delegate type that doesn't allow contravariance but I'm looking for a way to not have to change the signature of the API if possible.

Any ideas?


Solution

  • You won't be able to from inspecting the instance of the Action<in T> passed in. As you see, it actually is an Action<object> and there's nothing linking back to the fact that you wanted an Action<string>.

    However, instead of looking at the parameter, you should look at the signature of the method. This will always be Action<string> and reflecting/inspecting that will always give you the output you are looking for.