我正在创建一个.net WebAPI,以促进从Delphi代码到C#的逐步迁移,但我们的代码库非常大,超过150万行代码.因此,我们试图将应用程序分解为小库,我们可以加载到C#API中,然后随着时间的推移逐渐重写函数或服务.我们决定我们的库将导出3个常见函数: Initialize Execute DisposeStr我们创建的所有dll都将导出这些函数,这样我们就有了一种通用的方式来与本机代码进行通信.

我的问题是,我将拥有DelphiEmployeeService.csDelphiWorktimeService.cs等(可能超过DelphiEmployeeService.cs倍),并且我需要在每个服务包装器的开头有基本相同的行:

[LibraryImport("<DLLNAME>", EntryPoint = "Initialize")]
[return: MarshalAs(UnmanagedType.Bool)]
[UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
private static partial bool Initialize();

[LibraryImport("<DLLNAME>", EntryPoint = "Execute", StringMarshalling = StringMarshalling.Utf16)]
[UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
private static partial IntPtr Execute(string parameters);

[LibraryImport("<DLLNAME>", EntryPoint = "DisposeStr")]
[UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
private static partial void DisposeStr(IntPtr str);

为了解决这个问题,我想创建一个DelphiImplementation.cs的基类,但我不确定如何让后代注册要加载的DLL名称.

我想要的是类似于

public class DelphiImplementation
{
  protected abstract string LibraryName;

  [LibraryImport(LibraryName, EntryPoint = "Initialize")]
  [return: MarshalAs(UnmanagedType.Bool)]
  [UnmanagedCallConv(CallConvs = new Type[] {typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
  private static partial bool Initialize();

  [LibraryImport(LibraryName, EntryPoint = "Execute", StringMarshalling = StringMarshalling.Utf16)]
  [UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
  private static partial IntPtr Execute(string parameters);

  [LibraryImport(LibraryName, EntryPoint = "DisposeStr")]
  [UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
  private static partial void DisposeStr(IntPtr str);
}
public class EmployeeDelphiService : DelphiImplementation
{
  protected override string LibraryName => "Employee.dll"
}

这种事有可能吗

推荐答案

您可以使用NativeLibrary类动态加载DLL并执行函数.从函数指针创建委托,并将它们存储在类中以便调用它们应该是相当简单的.

public class DelphiImplementation
{
    protected abstract string LibraryName { get; }

    [return: MarshalAs(UnmanagedType.Bool)]
    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    protected delegate bool InitializeDelegate();

    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    protected delegate IntPtr ExecuteDelegate(string parameters);

    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    protected delegate void DisposeStrDelegate(IntPtr str);

    private IntPtr Handle { get; } = NativeLibrary.Load(LibraryName);

    protected InitializeDelegate Initialize { get; }

    protected ExecuteDelegate Execute { get; }

    protected InitializeDelegate DisposeStr { get; }

    protected DelphiImplementation()
    {
        Initialize = Marshal.GetDelegateForFunctionPointer<InitializeDelegate>(NativeLibrary.GetExport(Handle, nameof(Initialize)));        
        Execute = Marshal.GetDelegateForFunctionPointer<ExecuteDelegate>(NativeLibrary.GetExport(Handle, nameof(Execute)));
        DisposeStr = Marshal.GetDelegateForFunctionPointer<DisposeStrDelegate>(NativeLibrary.GetExport(Handle, nameof(DisposeStr)));
    }
}

你可以简单地做someImplementation.Initialize()个等等.

如果您想在使用后卸载DLL,则可以使用IDisposableusing.

public class DelphiImplementation : IDisposable
{
....

    public void Dispose()
    {
        NativeLibrary.Free(Handle);
    }
}

Csharp相关问答推荐

有没有方法让ASP.NET Core模型绑定器使用私有设置器来设置属性?

总是丢弃返回的任务和使方法puc无效之间有区别吗?

CsWin32如何创建PWSTR的实例,例如GetWindowText

MongoDB将JS查询转换为C#的问题

如何创建ASP.NET Core主机并在同一进程中运行请求

如何在Reflection. Emit中使用具有运行时定义的类型参数的泛型类型

C#中使用BouncyCastle计算CMac

如何修改中间件或其注册以正确使用作用域服务?

如何在C#中将对象[*,*]直接转换为字符串[*,*]?

在一个模拟上设置一个方法,该模拟具有一个参数,该参数是一个numc函数表达式

Nuget包Serilog.Sinks.AwsCloudwatch引发TypeLoadExceptions,因为父类型是密封的

有空容错运算符的对立面吗?

在.NET 8最低API中从表单绑定中排除属性

如何在不复制或使用输出的情况下定义项目依赖

在使用StringBuilder时,如何根据 colored颜色 设置为richTextBox中的特定行着色?

Blazor Server/.NET 8/在初始加载时调用异步代码是否冻结屏幕,直到第一次异步调用完成?

如何在Xamarin.Forms中检索PanGesture事件的位置?

如何对正方形格线进行对角分组

自定义ConsoleForMatter中的DI/Http上下文

使用';UnityEngineering.Random.Range()';的IF语句仅适用于极高的最大值