2016-12-12 1 views
1

Делегаты WaitCallback и Action имеют одну и ту же подпись. Тем не менее, как доказательство кода ниже, они не могут рассматриваться как один и тот же тип.Почему нельзя использовать делегат Action <Object> в качестве WaitCallback для Threadpool?

static void Main(string[] args) 
{ 
    WaitCallback wcb = (o) => Console.WriteLine("Hello from wcb delegate"); 
    ThreadPool.QueueUserWorkItem(wcb);//works 

    Action<object> action = (o) => Console.WriteLine("Hello from action<object> delegate"); 
    ThreadPool.QueueUserWorkItem(action);//does not compile: Cannot convert from Action<object> to WaitCallback 

    Console.ReadLine(); 
} 

У меня есть два вопроса по поводу этого наблюдения:

1) Почему это так, что делегаты с той же подписью, но с другим именем, не рассматриваются в качестве одного типа? Может ли команда дизайна языка выбрать по-другому или это могло бы привести к несоответствиям или другим проблемам?

2) Когда делегаты Action, где введены в .Net framework 2.0, WaitCallback уже существует. Интересно, было ли это не так, было ли оправдано введение дополнительного типа делегата WaitCallback вместо использования Action?

Спасибо, Хенк

ответ

0

С точки зрения типа системы зрения WaitCallback другой тип от Action<object> и там не существует неявное преобразование между ними. Таким образом, вы не можете использовать Action<object>, где ожидается WaitCallback. Фактическая методы и использовался в качестве делегатов, однако, только заботиться о совместимости их список аргументов и типа возвращаемого значения, поэтому вместо того, чтобы иметь анонимный метод, который вы могли бы иметь

private void Foo(object o) { 
    Console.WriteLine("Hello from actual method"); 
} 

и следующие строки будут работать без проблем :

WaitCallback wcb = Foo; 
Action<object> action = Foo; 
ThreadPool.QueueUserWorkItem(Foo); 

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

Спецификация также содержит следующее примечание:

типа делегата в C# являются эквивалентными имя, а не структурно эквивалентными. В частности, два разных типа делегатов, которые имеют одинаковые списки параметров и тип возвращаемого значения, считаются разными типами делегатов.

(Предупреждение: спекуляции, я не был на дизайн языка команде) Так что это был сознательный выбор, и учитывая то, что я написал выше, это не может быть невозможно, чтобы то, что вы просили, но «Является основным исключением из того, как работает разрешение перегрузки. Поэтому я предполагаю, что этот вызов был сделан для упрощения языка. Кроме того, еще в C# 1 дни, вероятно, было не так много делегатов, которые были на самом деле структурно совместимыми.

Что касается вашего второго пункта, они, вероятно, пошли бы с Action в этом случае. В качестве примера см. Метод Task.Run, который принимает вместо Action вместо пользовательского делегата. Для действий, которые не принимают ни одного или одного параметра, кажется довольно очевидным случаем, чтобы не вводить новый тип делегата. Однако для таких вещей, как Action<string, string, int, double> или эквивалентных типов Func, я предполагаю, что фактический именованный тип, который может быть документирован, будет намного лучше, чем использование общих типов Action или Func.

+0

Спасибо, Джои за ваш сложный ответ. Ваш способ формулировки дал мне больше информации о том, как работают делегаты. Ваше объяснение имен методов, именуемых делегатами, является отличным бонусом. – HenkGijsbert

Смежные вопросы