每当我深入研究反射器时,我都会遇到extern
没有来源的方法。我在http://msdn.microsoft.com/en-us/library/e59b22c5(v=vs.80).aspx阅读了 msdn 文档。我从那篇文章中得到的是extern
必须注入带有修饰符的方法。我将其解释为它的工作原理类似于抽象工厂模式。我还注意到我从未见过非静态外部方法。静态声明是必需的吗(我可以看到这有什么意义)?我仍然在这里猜测,我不确定它实际上是如何工作的。在我看来,编译器必须识别某些减轻处理的属性,但除了我遇到的属性之外,我不知道这些属性是什么,MethodImplAttribute
并且DllImportAttribute
来自 MSDN 示例。某人如何利用该extern
属性?它说,在许多情况下,这可以提高性能。另外,我将如何去研究extern
方法的来源Object.InternalGetEquals()
?
4 回答
考虑阅读 C# 规范的第 10.6.7 节,它回答了您的许多问题。为了您的方便,我在这里复制了一部分:
当方法声明包含 extern 修饰符时,该方法称为外部方法。外部方法在外部实现,通常使用 C# 以外的语言。因为外部方法声明不提供实际实现,所以外部方法的方法体只包含一个分号。外部方法可能不是通用的。extern 修饰符通常与 DllImport 属性结合使用,允许由 DLL(动态链接库)实现外部方法。执行环境可以支持其他机制,从而可以提供外部方法的实现。当外部方法包含 DllImport 属性时,方法声明还必须包含静态修饰符。
有人如何利用 extern 属性?
- 使用您选择的非托管语言编写代码。
- 将其编译为 DLL,导出代码的入口点。
- 创建一个互操作库,将方法定义为给定 DLL 中的外部方法。
- 从 C# 调用它。
- 利润!
我将如何研究像 Object.InternalGetEquals() 这样的外部方法的来源?
extern
用属性标记的方法[DllImport]
通常是对 C 库的调用。此功能对于调用 WinAPI 或遗留代码很有用。
这是来自 MSDN 的示例:
using System;
using System.Runtime.InteropServices;
class MainClass
{
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);
static int Main()
{
string myString;
Console.Write("Enter your message: ");
myString = Console.ReadLine();
return MessageBox(0, myString, "My Message Box", 0);
}
}
它调用MessageBox
在 Windowsuser32.dll
库中定义的。运行时在这里为您完成所有繁重的工作,尽管有时您需要手动管理内存。如果你弄错了签名,你的程序可能会在调用中失败,你可能会引入泄漏或者方法可能会返回完全不同的东西,所以要小心!我发现pinvoke.net是一个很好的工具来纠正不同 API 的签名。
.NET Framework中一些extern
没有[DllImport]
属性但用[MethodImpl (MethodImplOptions.InternalCall)]
属性修饰的方法通常是CLR本身实现的,也是用C编写的。有些这样的方法不能在 C# 中实现,因为它们自己管理运行时,有些是在 C 中实现的,因为它们的性能很关键,而且 C 更快。
这是 MSDN对它们的评价:
指定内部调用。内部调用是对在公共语言运行时本身内实现的方法的调用。
至于查看实际的实现代码,我怀疑您是否能够从 Microsoft 获得它,但有一些很酷的 CLR 替代实现,因此请务必检查它们。
extern
使用平台调用 (pinvoke) 来促进托管程序集调用非托管代码。该extern
关键字通知编译器它需要生成正确的代码以允许正确的数据编组。
我们在方法声明中使用“extern”修饰符。它用于表示该方法是在外部实现的。“extern”修饰符的一个常见用途是与 DllImport 属性一起使用。使用此属性管理非 C# 函数调用。如果您使用的是 extern 修饰符,那么您必须包含以下命名空间:
using System.Runtime.InteropServices;
语法类似于:
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);