Подтвердить что ты не робот

Как делегаты в С# лучше, чем указатели на функции в C/С++?

Делегаты в С# предлагают аналогичную функциональность, как указатели на функцию в C. Я слышал, как кто-то сказал, что "делегаты С# на самом деле лучше, чем указатели на функции в C". Как так? Пожалуйста, объясните с примером.

4b9b3361

Ответ 1

"Лучше" субъективно - но главными отличиями являются:

  • Введите безопасность. Делегату не только гарантированно ссылаться на действительный метод, он гарантированно относится к методу с правильной сигнатурой.
  • Это указатель связанного метода, то есть делегат может указывать на конкретный объект, на который можно вызвать делегат. Таким образом, делегат Action<string> может ссылаться на alice.GetName или bob.GetName, а не только на Person.GetName. Это может быть похоже на С++ "указатель на член" - я не уверен.

Кроме того, язык С# поддерживает закрытие через делегирование анонимным методам и лямбда-выражениям - например, захват локальных переменных процедуры объявления, которые делегат может ссылаться при последующем их выполнении. Это, строго говоря, не функция делегатов - она ​​включена компилятором С#, делающим магию для анонимных методов и лямбда-выражений, - но это все еще стоит упомянуть, потому что это позволяет много функциональных идиом в С#.

РЕДАКТИРОВАТЬ: Как отмечает CWF в комментариях, еще одно возможное преимущество делегатов С# заключается в том, что объявления типов делегатов легче читать многим. Разумеется, это может быть вопрос знакомства и опыта.

Ответ 2

Указатели всегда могут указывать на неправильное место:). Я могу указать на не-функцию или произвольное место в памяти.

Но с точки зрения функциональности указатели на функции могут делать все, что могут сделать делегаты.

Ответ 3

Одна вещь, которую делегат обеспечивает, что указатель на функцию C/С++ не является безопасностью типа. То есть в C/С++ вы можете перетащить указатель функции в переменную-указатель функции, объявленную с неправильной сигнатурой функции (или даже int double или хуже с соответствующим уговором), и компилятор будет рад создать код, который вызывает функция полностью неверна. В С# сигнатура типа должна соответствовать сигнатуре типа делегата, а также тому, как в конечном итоге вызывается делегат.

Ответ 4

Многие люди называют делегатов С# более "безопасными по типу", чем указатели на функции С++, и я действительно нахожу его вводящим в заблуждение. В действительности они не являются более безопасными для типов, поскольку указатели на функции С++. Пример кода С++ (скомпилированный MSVS 2005 SP1):

typedef int (*pfn) (int);

int f (int) {
   return 0;
}

double d (int) {
   return 1;
}

int main()
{
   pfn p=f; // OK
   p=d; // error C2440: '=' : cannot convert from 'double (__cdecl *)(int)' to 'pfn'
   p=(pfn)d;
}

Итак, как видно из приведенного выше примера, если вы не используете "грязные хаки" для "заткновения" компилятора, легко обнаруживается несоответствие типов, и сообщение компилятора легко понять. Так что это безопасность типа, насколько я понимаю.

Относительно "ограниченности" указателей на функции-члена. Действительно, в С++ указатель-член не связан, указатель на функцию-член должен применяться к type, которая соответствует сигнатуре указателя участника. Пример:

class A {
public:

   int f (int) {
      return 2;
   }

};

typedef int (A::*pmfn) (int);

int main()
{
   pmfn p=&(A::f);
   // Now call it.
   A *a=new A;
   (a->*p)(0); // Calls A::f
}

Опять же, все абсолютно безопасно.