何时在不使用[DllImport]属性的情况下使用extern关键字是否合适?

时间:2016-06-24 13:49:07

标签: c# .net dllimport

我今天重读了一些.Net文档,当时我注意到extern keywords documentation声明的第一部分:

  

extern修饰符用于声明从外部实现的方法。 当您使用Interop服务调用非托管代码时,extern修饰符的常用 与DllImport属性一起使用。

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

我已经通过Google和MSDN搜索了多个查询,我无法找到关于何时使用extern关键字的案例或解释,而没有将该方法定义为从外部方法导入unmanaged dll。

如何在不定义方法定义的extern属性的情况下,如何以及何时使用[DllImport(...)]关键字?

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

1 个答案:

答案 0 :(得分:8)

我使用它的一个案例是,如果我是Microsoft开发人员实现对C​​LR本身定义的方法的调用。就像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接口的调用。显然,InternalCall 的使用mscorlib之外有效。您通常不会自己在C#中编写此类代码;当您添加COM类型库作为参考时,它是按需生成的。

C#语言规范比MSDN更详细:

  

extern修饰符通常与DllImport结合使用   属性(第17.5.1节),允许外部方法实现   DLL(动态链接库)。执行环境可能会支持   外部方法的实现可以是其他机制   提供。

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

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