Есть ли способ обнаружить исходный тип общего аргумента экземпляра действияделегировать? - PullRequest
2 голосов
/ 18 ноября 2011

Есть ли способ найти объявленный тип общего аргумента экземпляра делегата Action?

В следующем коде функция WriteGenericArgumentType ожидает и экземпляр Action<String>, но, поскольку Action<in T> допускает, что вызывающие контравариантности функции могут вызывать ее с помощью 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];
}

Однако мне нужно иметь возможность обнаружить общий тип аргумента, который был определен в сигнатуре WriteGenericArgumentType из экземпляра делегата, который передается в DiscoverGenericArgumentType.

Когда код запускается, я получаю следующий вывод:

String
Object

Но мне нужно, чтобы это было:

String
String

Для моих целей я не могу изменить сигнатуру DiscoverGenericArgumentType, и мне нужна эта функция для возврата string в качестве типа.

Я знаю, что могу создать свой собственный тип общего делегата, который не допускает контравариантности, но я ищу способ не менять сигнатуру API, если это возможно.

Есть идеи?

Ответы [ 4 ]

3 голосов
/ 18 ноября 2011

Вы не сможете проверить экземпляр переданного Action<in T>. Как видите, на самом деле равно Action<object>, и нет ничего связывающегона тот факт, что вы хотели Action<string>.

Однако вместо того, чтобы смотреть на параметр, вы должны посмотреть на сигнатуру метода .Это всегда будет Action<string> и отражает / проверяет , что всегда даст вам результат, который вы ищете.

2 голосов
/ 18 ноября 2011

Будет ли это работать для вас?

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

Он делает то, что вы просите, но я не знаю, можете ли вы изменить сигнатуру вашего метода, чтобы потребовать определенную подпись делегата.

2 голосов
/ 18 ноября 2011

Вы не можете сделать это, потому что вы не меняете объект.Подумайте:

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

В обоих случаях вы передаете одинаковую ссылку на DiscoverGenericArgumentType, так как же это может сказать, что вы имеете в виду?

0 голосов
/ 19 ноября 2011

Один из способов, которым я могу обойти это, - обернуть делегата / обнаружить тип в точке, в которой я точно знаю тип:

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