2013-06-20 4 views
12

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

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 

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

+2

Я не могу дать вам аргументы, но делегаты были оригинальной особенностью языка. С тех пор они добавили лямбда-методы, [Действия] (http://msdn.microsoft.com/en-us/library/system.action.aspx) и [Funcs] (http://msdn.microsoft.com/ en-us/library/bb534960.aspx), которые не страдают от одной и той же проблемы. – Brandon

+0

@Brandon Что? Lambdas преобразуются в делегаты (или деревья выражений), а 'Action' и 'Func' * являются * просто делегированными типами, поэтому они соответствуют точно таким же правилам. – svick

+0

Проверки делегатов также проверяются во время выполнения. Это было оптимизировано, важный вид оптимизации, поддерживается только строгий тип. Это быстро. –

ответ

23

In C# all delegate types are incompatible with one another, even if they have the same signature. What is the reasoning behind this behaviour and language design decision?

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

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

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

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

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

+1

Я должен буду помнить этот термин, * * misfeature * '. –

+1

Я помню с любовью короткое время, когда у меня был ответ с большим количеством голосов, чем Эрик Липперт. –

15

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

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   
2

Делегат не что иное, как просто еще тип. Они несовместимы по той же причине class A {} и class B {} были бы несовместимы.

delegate void D1(); 

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

class D1 : MulticastDelegate { .... } 
Смежные вопросы