
go 原生不支持直接加载和调用 .net 程序集(如 c# 编译的 dll),因其基于 clr 运行时,与 windows 传统 win32 dll 结构不同;需借助桥接工具(如 go-dotnet)通过 .net core/5+ 运行时宿主机制实现互操作。
go 原生不支持直接加载和调用 .net 程序集(如 c# 编译的 dll),因其基于 clr 运行时,与 windows 传统 win32 dll 结构不同;需借助桥接工具(如 go-dotnet)通过 .net core/5+ 运行时宿主机制实现互操作。
在 Go 中直接使用 syscall.NewLazyDLL 调用 C# 编译的 .dll(如 MathForGo.dll)必然失败——这不是路径、导出名或调用约定的问题,而是根本性架构差异所致:
- ✅ C/C++ 编译的 DLL:导出标准 Win32 函数(__declspec(dllexport)),可被 syscall 或 golang.org/x/sys/windows 加载;
- ❌ C# 编译的程序集(即使设为“类库”并启用 COM 互操作):默认生成的是托管 IL 字节码,依赖 .NET 运行时(CoreCLR 或 Mono)执行,不是原生 PE 导出函数,无法被 Go 的系统调用层识别。
正确方案:使用 go-dotnet 桥接
go-dotnet 是目前最成熟的 Go ↔ .NET 互操作库,它通过嵌入 .NET 运行时(需 .NET 6+ SDK / Runtime),在 Go 进程内启动托管环境,并提供 Go 侧 API 调用 C# 方法。
✅ 示例:从 Go 调用 C# 的 Add(int, int) 方法
1. C# 项目(.NET 6+ 类库)
创建 MathLib.csproj:
<project sdk="Microsoft.NET.Sdk"><propertygroup><targetframework>net6.0</targetframework><implicitusings>enable</implicitusings><nullable>enable</nullable></propertygroup></project>
Math.cs:
using System.Runtime.InteropServices;
namespace MathLib
{
public static class Calculator
{
public static int Add(int a, int b) => a + b;
}
}
编译:dotnet build -c Release
2. Go 项目(启用 go-dotnet)
安装依赖:
go get github.com/matiasinsaurralde/go-dotnet
main.go:
package main
import (
"fmt"
"github.com/matiasinsaurralde/go-dotnet"
)
func main() {
// 初始化 .NET 运行时(自动查找本地 .NET 6+ Runtime)
err := dotnet.Initialize()
if err != nil {
panic("Failed to initialize .NET: " + err.Error())
}
defer dotnet.Shutdown()
// 加载程序集(路径为 bin/Release/net6.0/MathLib.dll)
asm, err := dotnet.LoadAssembly("./bin/Release/net6.0/MathLib.dll")
if err != nil {
panic("Failed to load assembly: " + err.Error())
}
// 获取类型并调用静态方法
calcType := asm.GetType("MathLib.Calculator")
result, err := calcType.InvokeStaticMethod("Add", 2, 3)
if err != nil {
panic("Call failed: " + err.Error())
}
fmt.Printf("2 + 3 = %v\n", result) // 输出:2 + 3 = 5
}
3. 运行前提
- 本地已安装 .NET 6 或更高版本运行时(非仅 SDK);
- Go 版本 ≥ 1.18;
- Windows/macOS/Linux 均支持(跨平台基于 .NET 自身兼容性)。
⚠️ 注意事项与替代思路
- 不要尝试 P/Invoke + UnmanagedExports:虽有 DllExport 工具可导出非托管函数,但稳定性差、调试困难,且不支持泛型、引用类型等,仅适合极简场景;
- 避免 COM 注册:C# COM 暴露在现代 Go 中无原生支持,且需管理员权限注册,不符合云原生部署习惯;
- 生产建议:对高可靠性要求场景,推荐将 C# 逻辑封装为 gRPC/HTTP 微服务(如 ASP.NET Core Web API),Go 通过网络调用——更解耦、易监控、跨语言友好。
总之,Go 与 C# 互操作可行,但必须绕过“直接 DLL 加载”这一误区,转而采用运行时桥接(go-dotnet)或进程间通信(IPC/API)方案。前者适合低延迟嵌入式集成,后者更适合分布式系统架构。











