什么时候使用 extern 关键字而不使用 [DllImport] 属性是合适的?
When is it appropriate to use the extern keyword without using the [DllImport] attribute?
我今天重新阅读一些 .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
的 "a common use" 是与 DllImport 属性一起使用的。这意味着还有其他不需要 DllImport 的用例。我不必将许多外部非托管库集成到我的应用程序中,但在所有情况下,链接方法都是使用 DllImport 定义的。
我已经通过 Google 和 MSDN 搜索了多个查询,但找不到在不将方法定义为外部方法导入的情况下何时使用 extern
关键字的案例或解释来自非托管 dll。
如何以及何时使用 extern
关键字而不在方法定义中定义 [DllImport(...)]
属性?
请注意,这并不特定于在定义别名时使用 extern
。这是关键字的不同用法,这种情况在 MSDN C# 语言参考中是 outlined in a different article。
如果我是一名 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[=11=]")]
[Guid("00024500-0000-0000-C000-000000000046")]
[TypeLibType(2)]
[ComImport]
public class ApplicationClass {
// ...
[DispId(302)]
[MethodImpl(MethodImplOptions.InternalCall)]
public virtual extern void Quit();
// ...
}
}
这些属性允许运行时将方法调用解析为对 COM 接口的调用。显然,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 节中有描述,"Method implementation metadata"(DllImport
和 InternalCall
似乎是目前唯一可用的方法)。
C# 编译器将允许您将方法标记为 extern
而 不 使用任何属性来指示实现所在的位置,但任何具有此类方法的类型将在运行时产生 TypeLoadException
。
我今天重新阅读一些 .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
的 "a common use" 是与 DllImport 属性一起使用的。这意味着还有其他不需要 DllImport 的用例。我不必将许多外部非托管库集成到我的应用程序中,但在所有情况下,链接方法都是使用 DllImport 定义的。
我已经通过 Google 和 MSDN 搜索了多个查询,但找不到在不将方法定义为外部方法导入的情况下何时使用 extern
关键字的案例或解释来自非托管 dll。
如何以及何时使用 extern
关键字而不在方法定义中定义 [DllImport(...)]
属性?
请注意,这并不特定于在定义别名时使用 extern
。这是关键字的不同用法,这种情况在 MSDN C# 语言参考中是 outlined in a different article。
如果我是一名 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[=11=]")]
[Guid("00024500-0000-0000-C000-000000000046")]
[TypeLibType(2)]
[ComImport]
public class ApplicationClass {
// ...
[DispId(302)]
[MethodImpl(MethodImplOptions.InternalCall)]
public virtual extern void Quit();
// ...
}
}
这些属性允许运行时将方法调用解析为对 COM 接口的调用。显然,InternalCall
在 mscorlib
之外有效。您通常不会自己用 C# 编写此类代码;它是在您添加 COM 类型库作为引用时按需生成的。
C# 语言规范比 MSDN 更详细:
The
extern
modifier is typically used in conjunction with aDllImport
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 节中有描述,"Method implementation metadata"(DllImport
和 InternalCall
似乎是目前唯一可用的方法)。
C# 编译器将允许您将方法标记为 extern
而 不 使用任何属性来指示实现所在的位置,但任何具有此类方法的类型将在运行时产生 TypeLoadException
。