c# - 什么时候使用 extern 关键字而不使用 [DllImport] 属性是合适的?

标签 c# .net dllimport

今天我正在重新阅读一些 .Net 文档,这时我注意到 extern keywords documentation 的第一部分声明:

The extern modifier is used to declare a method that is implemented externally. A common use of the extern modifier is with the DllImport attribute when you are using Interop services to call into unmanaged code.

引起我注意的是文档指出 extern 的“常见用途”是它与 DllImport 属性一起使用。这意味着还有其他不需要 DllImport 的用例。我不必将许多外部非托管库集成到我的应用程序中,但在所有情况下,链接方法都是使用 DllImport 定义的。

我通过 Google 和 MSDN 搜索了多个查询,但找不到关于 extern 何时出现的案例或解释。将在不将方法定义为从非托管 dll 导入的外部方法的情况下使用关键字。

您将如何以及何时使用 extern未定义 [DllImport(...)] 的关键字方法定义上的属性?

请注意,这并非特定于使用 extern定义别名时。这是关键字的不同用法,这种情况是 outlined in a different article在 MSDN C# 语言引用中。

最佳答案

我会使用它的一种情况是,如果我是一名 Microsoft 开发人员,要实现对 CLR 本身中定义的方法的调用。就像在 GC._WaitForFullGCApproach 中一样:

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int _WaitForFullGCApproach(int millisecondsTimeout);

注意:没有DllImport。当然这有点作弊——这仍然是对非托管方法的调用,只是没有显式引用 DLL。但是,凡人无法调用此类代码,因为它仅在 mscorlib 程序集中有效。

InternalCall 的另一个应用是为 COM 生成的互操作类型:

namespace Microsoft.Office.Interop.Excel {
    [DefaultMember("_Default")]
    [ClassInterface(0)]
    [ComSourceInterfaces("Microsoft.Office.Interop.Excel.AppEvents\0")]
    [Guid("00024500-0000-0000-C000-000000000046")]
    [TypeLibType(2)]
    [ComImport]
    public class ApplicationClass {
        // ...
        [DispId(302)]
        [MethodImpl(MethodImplOptions.InternalCall)]
        public virtual extern void Quit();
        // ...
    }
}

属性允许运行时将方法调用解析为对 COM 接口(interface)的调用。显然,InternalCall mscorlib 之外的使用是有效的。您通常不会自己用 C# 编写此类代码;它是在您添加 COM 类型库作为引用时按需生成的。

C# 语言规范比 MSDN 稍微详细一些:

The extern modifier is typically used in conjunction with a DllImport attribute (§17.5.1), allowing external methods to be implemented by DLLs (Dynamic Link Libraries). The execution environment may support other mechanisms whereby implementations of external methods can be provided.

从实现的角度来看,将方法标记为extern 只会起到将方法的RVA(相对虚拟地址)设置为0 的作用,将其标记为没有实现。像 DllImport(和 MethodImpl)这样的属性对于向运行时描述如何定位方法的实际实现是必要的。这在 ECMA-335 的第 I.9.4 节“方法实现元数据”中有所描述(DllImportInternalCall 似乎是目前唯一可用的方法)。

C# 编译器将允许您将方法标记为 extern 并且使用任何属性来指示实现所在的位置,但是具有此类方法的任何类型都将导致在运行时的 TypeLoadException 中。

关于c# - 什么时候使用 extern 关键字而不使用 [DllImport] 属性是合适的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38015024/

相关文章:

c# - 如何在 C# 中缩放和绘制绘图

c# - 获取更新查询的 sql 语法错误

c# - 移动窗口切换时如何保持时间引用? (统一)

.net - .Net WCF NAT 穿越的最佳实践

c# - 使用回调调用 MiniDumpWriteDump

c++ - 错误: function definition is marked dllimport

c# - 将指针(即 int[])传递给 DLL 时, "fixed"真的能保证任何事情吗?

c# - 这是动态的错误吗?

c# - 尝试在 C# 中创建数学输入面板

c# - 从动态 xml 转换为 C# 对象