Почему все типы делегатов несовместимы друг с другом?

В С# все типы делегатов несовместимы друг с другом, даже если они имеют одну и ту же подпись. В качестве примера:

delegate void D1();
delegate void D2();

D1 d1 = MethodGroup;
D2 d2 = d1;                           // compile time error
D2 d2 = new D2 (d1);                  // you need to do this instead

В чем причина такого поведения и решения для языкового дизайна.

Ответ 1

В С# все типы делегатов несовместимы друг с другом, даже если они имеют одну и ту же подпись. В чем причина такого поведения и решения по языковому дизайну?

Во-первых, я считаю, что справедливо сказать, что многие разработчики времени и языка сожалеют об этом решении. Структурная типизация на делегатах, то есть сопоставление по сигнатуре, является часто запрашиваемой функцией, и кажется странным, что Func<int, bool> и Predicate<int> не могут быть свободно назначены друг другу.

Обоснование решения, насколько я понимаю, - и я спешу добавить, что это решение было принято около шести лет, прежде чем я начал работу с командой С#, - это то, что ожидалось, что будут типы делегатов с семантикой. Вы хотите, чтобы это была ошибка типа:

AnyFunction<int, int> af = x=> { Console.WriteLine(x); return x + y; };
PureFunction<int, int> pf = af;

"Чистая" функция - это функция, которая производит и не потребляет побочных эффектов, не потребляет никакой информации за пределами своих аргументов и возвращает согласованное значение при предоставлении тех же аргументов. Понятно, что af выдает не менее двух из них и поэтому не следует присваивать pf как неявное преобразование.

Но семантически загруженные типы делегатов никогда не происходили, так что теперь это немного неправильно.

Ответ 2

В основном потому, что компилятор делает для вас два класса. По той же причине вы не можете:

class A {}
class B {}

void Main()
{
    A a = new A();
    B b = a;
}

Например, следующий код

void Main() {}

delegate void D();
class C {}

Код IL:

D.Invoke:

D.BeginInvoke:

D.EndInvoke:

D..ctor:

C..ctor:
IL_0000:  ldarg.0     
IL_0001:  call        System.Object..ctor
IL_0006:  ret         

Ответ 3

Делегат - это всего лишь другой тип. Они несовместимы по той же причине class A {} и class B {} были бы несовместимы.

delegate void D1();

Будет примерно скомпилирован примерно так:

class D1 : MulticastDelegate { .... }