简体   繁体   中英

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?

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.

You can't do this, because you're not changing the object. Consider:

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

You're passing an identical reference to DiscoverGenericArgumentType in both cases, so how could it possibly tell what you mean?

Would this work for you?

static Type DiscoverGenericArgumentType<T>(Action<T> action )
{
    return typeof(T);
}

It does what you're asking for, but I don't know if you are able to change your method signature to require a specific delegate signature.

One way I can possibly get around this is to wrap the delegate / discover the type at the point I for sure know the type like so:

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

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

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

static Action<T> Wrap<T>( Action<T> action )
{
    return new Action<T>( o => action( o ) );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM