如何在C#中实现C ++样式函数指针,而不使用委托

我正在学习C#中的指针,并且好奇如果可以在C#中使用C ++样式函数指针。 是的,我知道C#有自己的等效function指针概念(称为委托)。 但我只是想知道使用C#中的指针是否可以实现相同,而不使用委托。

如果在C#中使用指针完全合法(使用不安全选项)并且指针语义几乎与C / C ++类似,那么在我看来,也应该能够使用C / C ++样式函数指针。 请指导我这个。 可能吗? 如果是的话怎么样?如果不是那么为什么?

请注意C#和C / C ++中指针使用的相似性,如下例所示

/* Using pointers in C# (Very similar to C/C++) */ using System; namespace UnsafeCodeApplication { class TestPointer { public unsafe static void Main() { int[] list = {10, 100, 200}; fixed(int *ptr = list) /* let us have array address in pointer */ for ( int i = 0; i < 3; i++) { Console.WriteLine("Address of list[{0}]={1}",i,(int)(ptr + i)); Console.WriteLine("Value of list[{0}]={1}", i, *(ptr + i)); } Console.ReadKey(); } } } 

其他答案注意到C#没有任何内置支持,即使在不安全模式下,函数指针也是正确的。

有趣的是要考虑实现此function需要什么。 实际上,我已经在2010年的未发布的C#原型版中实现了这个function? 那时候。 也许2011年。

我们决定对原型进行审查,结果是语法不够愉快,并且使用案例不足以certificate推进该function的合理性。

首先,该function对代表的吸引人的好处是什么? 委托是类型安全的,并且很好地捕获对绑定到其接收器的函数的引用的语义。 但是,在某些“系统”场景中 – 首先使用原始指针指向内存的相同场景 – 委托只是过于重量级。 它们被垃圾收集,它们增加了收集压力,与指针大小相比它们是一个大对象,它们在每次调用时都有成本,等等。 或者,您可能正在构建自己的自定义布局vtable,以便与一些特别讨厌的非托管代码进行互操作,并且您希望调用一个刚刚放在vtable中的函数指针。 等等。

CLR有必要的指令: calli ,一个指针间接调用。 但是C#中没有任何语法结构会导致C#编译器发出这条指令。

所以有什么问题? 只需添加一些导致它被发出的语法,对吧?

问题是:什么语法? 为了确保CLR的物理堆栈保持正确对齐, 编译器必须知道通过指针调用的方法的签名 。 当然,我们已经有了一种机制来说明方法的签名是什么:称为委托 ,我们已经拒绝使用这样的东西。 此外,请记住,我们在这里谈论的是实际将被操纵的物理堆栈,而不是CLR的抽象评估堆栈。 调用的函数的签名必须包括例如函数指针是cdecl还是syscall。

我们挣扎了一段时间才想出一些看起来并不可怕的东西,无论我们尝试哪种方式,它看起来都更加可怕。 我实际上不记得我们最终为原型实现的符号; 我想我可能已经阻止了它。 我可能会在我的笔记中找到它,但不幸的是我现在没有时间看。

该function仍然不断提出。 C#团队目前的管理层在低级别应用程序中使用托管语言有着悠久的历史,所以如果你有一个强大的用例,现在可能是再次推销它的好时机。

在CLR的支持下,C#语言将您限制为安全的不安全代码。 函数指针属于不安全的不安全类别,它们很容易使堆栈失衡。 这是一个令人讨厌的事故,会产生长期后果,导致代码在事故发生后长期行为不端。 这个网站的名字有一个很好的理由,这种bug是SOE因子。 甚至C ++编译器也会添加运行时检查以validation是否发生了堆栈不平衡。

你还有选择。 您可以使用Reflection.Emit或C ++ / CLI来使用原始函数指针。 或者通过使用Delegate.DynamicInvoke()实现道德等效。 后者始终是安全的,CLR执行运行时检查以validation是否传递了足够的参数。

这肯定是你应该考虑的解决方案,尽管你不清楚为什么要问。 代表们通过CLR中的大量代码进行了非常微优化,以使其快速。 该代码与Reflection.Emit相同,但在机器代码中。 你无法击败它。

不,C#中没有任何东西比C ++更接近代表的函数指针。 C#指针可以按以下类型操作:

  • sbyte,byte,short,ushort,int,uint,long,ulong,char,float,double,decimal或bool。
  • 任何枚举类型。
  • 任何指针类型。
  • 任何用户定义的结构类型,仅包含非托管类型的字段。

资料来源: https : //msdn.microsoft.com/en-us/library/y31yhkeb.aspx

并不总是可以将指针赋予用户,因为它是在本机代码中完成的。 C#代码编译为CLR而不是本机代码。

在.NET 1.1中,有Econo-JIT模式,其中可以在调用函数后删除函数的本机代码。 每次调用函数时,函数都可以有不同的地址。

C#没有指向函数的指针,事实上,C#指向值类型的唯一原因是与C / C ++和Win API互操作。 代表们为您提供服务。

C#是与C ++完全不同的编码范例。 不要让语义上的相似性让你感到困惑。 两种非常不同的语言,需要非常不同的心态。