C#中的委托如何比C / C ++中的函数指针更好?

C#中的委托提供与C中的函数指针类似的function。我听到有人说“C#委托实际上比C中的函数指针更好”。 怎么会? 请举例说明。

“更好”是主观的 – 但主要的区别是:

  • 类型安全。 委托不仅保证引用有效方法,而且保证引用具有正确签名的方法。
  • 它是一个绑定方法指针 – 也就是说,委托可以指向要调用委托的特定对象。 因此, Action委托可以引用alice.GetNamebob.GetName而不仅仅是Person.GetName 。 这可能类似于C ++“指向成员的指针” – 我不确定。

此外,C#语言通过委托支持对匿名方法和lambda表达式的闭包 – 即捕获声明过程的局部变量,委托可以在以后执行时引用该变量。 这并不严格地说是代理的一个特性 – 它由C#编译器在匿名方法和lambda表达式上做了一些魔术 – 但它仍然值得一提,因为它在C#中实现了很多function习惯用法。

编辑:正如CWF在评论中指出的那样,C#委托的另一个可能的优点是委托类型声明对于许多人来说更容易阅读。 当然,这可能是熟悉和经验的问题。

指针总是指向错误的地方:)即它可以指向内存中的非function或任意位置。

但就function而言,函数指针可以执行委托可以执行的任何操作。

委托提供C / C ++函数指针不是类型安全的一件事。 也就是说,在C / C ++中,你可以将一个函数指针推入一个用错误的函数签名声明的函数指针变量(或者甚至是一个带有适当的同轴的双重或更糟的int),并且编译器将很乐意生成调用的代码function完全错误。 在C#中,函数的类型签名必须与委托的类型签名以及最终调用委托的方式相匹配。

许多人将C#委托称为比C ++函数指针更“类型安全”,我真的觉得它具有误导性。 实际上,它们不再是C ++函数指针的类型安全。 示例C ++代码(由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; } 

因此,从上面的示例可以看出,除非使用“脏黑客”来“关闭”编译器,否则很容易检测到类型不匹配,并且编译器的消息很容易理解。 所以这就是我理解的类型安全。

关于成员函数指针的“边界”。 实际上,在C ++中,指向成员的指针没有绑定,成员函数指针必须应用于与成员指针的签名匹配的类型变量。 一个例子:

 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 } 

同样,一切都是完全类型安全的。