我怎样才能实现自己的外部类型?

Chr*_*gan 11 c# refactoring extern automated-refactoring .net-3.5

在我们的产品中,我们有称为"服务"的东西,它们是产品不同部分之间的基本交流方式(尤其是语言之间 - 内部语言,C,Python和.NET).

目前,代码是这样的(Services.Execute利用params object[] args):

myString = (string)Services.Execute("service_name", arg1, arg2, ...);
Run Code Online (Sandbox Code Playgroud)

我更愿意能够编写这样的代码并获得类型检查和更简洁的代码的好处:

myString = ServiceName(arg1, arg2, ...);
Run Code Online (Sandbox Code Playgroud)

这可以通过一个简单的功能来实现,

public static string ServiceName(int arg1, Entity arg2, ...)
{
    return (string)Services.Execute("service_name", arg1, arg2, ...);
}
Run Code Online (Sandbox Code Playgroud)

但这是相当冗长的,并且在执行大量服务时并不那么容易管理,正如我打算做的那样.

看看如何externDllImportAttribute工作,我希望有可能通过这样的方式来解决这个问题:

[ServiceImport("service_name")]
public static extern string ServiceName(int arg1, Entity arg2, ...);
Run Code Online (Sandbox Code Playgroud)

但我根本不知道如何实现这一点,似乎无法找到任何文档(extern似乎是一个相当模糊的定义问题).我发现最接近的是一个有点相关的问题,如何为.NET中的extern方法提供自定义实现?无论如何,这并没有真正回答我的问题而且有些不同.C#语言规范(特别是在4.0版,第10.6.7节,外部方法中)没有帮助.

所以,我想提供外部方法的自定义实现; 这可以实现吗?如果是这样,怎么样?

Han*_*ant 5

C# extern关键字的作用很小,它只是告诉编译器方法声明没有主体。编译器会做一个最低限度的检查,它坚持你也提供一个属性,任何事情都可以。所以这个示例代码将编译得很好:

   class Program {
        static void Main(string[] args) {
            foo();
        }

        class FooBar : Attribute { }

        [FooBar]
        static extern void foo();
    }
Run Code Online (Sandbox Code Playgroud)

但是当然它不会运行,抖动在声明中举起了手。这是实际运行此代码所需的内容,为此生成适当的可执行代码是抖动的工作。需要的是抖动识别该属性。

您可以在SSCLI20 发行版中的抖动源代码、clr/src/md/compiler/custattr.cpp 源代码文件、RegMeta::_HandleKnownCustomAttribute() 函数中看到这一点。这是 .NET 2.0 准确的代码,我不知道影响方法调用的添加内容。您将看到它处理与方法调用的代码生成相关的以下属性,该类型将使用extern关键字:

  • [DllImport],你肯定知道

  • [MethodImpl(MethodImplOptions.InternalCall)],一个用于在 CLR 而不是框架中实现的方法的属性。它们是用 C++ 编写的,CLR 有一个链接到 C++ 函数的内部表。一个典型的例子是 Math.Pow() 方法,我在这个答案中描述了实现细节。该表不可扩展,它在 CLR 源代码中是硬烤的

  • [ComImport],该属性将接口标记为在别处实现,总是在 COM 服务器中。您很少直接对该属性进行编程,而是使用由 Tlbimp.exe 生成的互操作库。此属性还需要 [Guid] 属性来提供接口所需的 guid。这在其他方面类似于 [DllImport] 属性,它生成对非托管代码的 pinvoke 类型的调用,但使用 COM 调用约定。这当然只有在您的机器上确实有所需的 COM 服务器时才能正常工作,否则它可以无限扩展。

在此函数中可以识别更多属性,但它们与调用在别处定义的代码无关。

因此,除非您编写自己的抖动,否则使用extern不是获得所需内容的可行方法。如果你想继续这个项目,你可以考虑 Mono 项目。

纯托管的常见可扩展性解决方案是大部分被遗忘的 System.AddIn 命名空间、非常流行的 MEF 框架和 AOP 解决方案,如 Postsharp。