的使用以及 .NET 与 Go 互相调用
背景其实规划这篇文章有一段时间了但是比较懒所以一直拖着没写。最近时总更新太快了太卷了所以借着 .NET 7 正式版发布熬夜写完这篇文章希望能够追上时总的一点距离。本文主要介绍如何在 .NET 和 Go 语言中如何生成系统(Windows)动态链接库又如何从代码中引用这些库中的函数。在 .NET 部分介绍如何使用 AOT、减少二进制文件大小、使用最新的 [LibraryImport] 导入库函数在 Go 语言部分介绍如何使用 GCC 编译 Go 代码、如何通过 syscall 导入库函数。在文章中会演示 .NET 和 Go 相互调用各自生成的动态链接库以及对比两者之间的差异。本文文章内容以及源代码可以 https://github.com/whuanle/csharp_aot_golang 中找到如果本文可以给你带来帮助可以到 Github 点个星星嘛。C# 部分环境要求SDK.NET 7 SDK、Desktop development with C workload。IDEVisual Studio 2022Desktop development with C workload 是一个工具集里面包含 C 开发工具需要在 Visual Studio Installer 中安装如下图红框中所示。image-20221109182246338创建一个控制台项目首先创建一个 .NET 7 控制台项目名称为 CsharpAot。打开项目之后基本代码如图所示image-20221109184702539我们使用下面的代码做测试public class Program{static void Main(){Console.WriteLine(“C# Aot!”);Console.ReadKey();}}体验 AOT 编译这一步可以参考官方网站的更多说明https://learn.microsoft.com/zh-cn/dotnet/core/deploying/native-aot/为了能够让项目发布时使用 AOT 模式需要在项目文件中加上 true 选项。image-20221109184850615然后使用 Visual Studio 发布项目。发布项目的配置文件设置需要按照下图进行配置。image-20221109201612226AOT 跟 生成单个文件 两个选项不能同时使用因为 AOT 本身就是单个文件。配置完成后点击 发布然后打开 Release 目录会看到如图所示的文件。image-20221109194100927.exe 是独立的可执行文件不需要再依赖 .NET Runtime 环境这个程序可以放到其他没有安装 .NET 环境的机器中运行。然后删除以下三个文件CsharpAot.exp CsharpAot.lib CsharpAot.pdb光用 .exe 即可运行其他是调试符号等文件不是必需的。剩下 CsharpAot.exe 文件后启动这个程序image-20221109194207563C# 调用库函数这一部分的代码示例是从笔者的一个开源项目中抽取出来的这个项目封装了一些获取系统资源的接口以及快速接入 Prometheus 监控。不过很久没有更新了最近没啥动力更新读者可以点击这里了解一下这个项目https://github.com/whuanle/CZGL.SystemInfo/tree/net6.0/src/CZGL.SystemInfo/Memory因为后续代码需要所以现在请开启 “允许不安全代码”。本小节的示例是通过使用 kernel32.dll 去调用 Windows 的内核 API(Win32 API)调用 GlobalMemoryStatusEx 函数 检索有关系统当前使用物理内存和虚拟内存的信息。使用到的 Win32 函数可参考https://learn.microsoft.com/zh-cn/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex关于 .NET 调用动态链接库的方式在 .NET 7 之前通过这样调用[DllImport(Kernel32.dll, CharSet CharSet.Auto, SetLastError true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern Boolean GlobalMemoryStatusEx(ref MemoryStatusExE lpBuffer);在 .NET 7 中出现了新的操作方式 [LibraryImport]。文档是这样介绍的Indicates that a source generator should create a function for marshalling arguments instead of relying on the runtime to generate an equivalent marshalling function at run time.指示源生成器应创建用于编组参数的函数而不是依赖运行库在运行时生成等效的编组函数。简单来说就是我们要使用 AOT 写代码然后代码中引用到别的动态链接库时需要使用 [LibraryImport] 引入这些函数。笔者没有在 AOT 下测试过 [DllImport]读者感兴趣可以试试。新建两个结构体 MEMORYSTATUS.cs、MemoryStatusExE.cs 。MEMORYSTATUS.cs public struct MEMORYSTATUS{internal UInt32 dwLength;internal UInt32 dwMemoryLoad;internal UInt32 dwTotalPhys;internal UInt32 dwAvailPhys;internal UInt32 dwTotalPageFile;internal UInt32 dwAvailPageFile;internal UInt32 dwTotalVirtual;internal UInt32 dwAvailVirtual;}MemoryStatusExE.cs public struct MemoryStatusExE{////// 结构的大小以字节为单位必须在调用 GlobalMemoryStatusEx 之前设置此成员可以用 Init 方法提前处理////// 应当使用本对象提供的 Init 而不是使用构造函数internal UInt32 dwLength;/// summary /// 一个介于 0 和 100 之间的数字用于指定正在使用的物理内存的大致百分比0 表示没有内存使用100 表示内存已满。 /// /summary internal UInt32 dwMemoryLoad; /// summary /// 实际物理内存量以字节为单位 /// /summary internal UInt64 ullTotalPhys; /// summary /// 当前可用的物理内存量以字节为单位。这是可以立即重用而无需先将其内容写入磁盘的物理内存量。它是备用列表、空闲列表和零列表的大小之和 /// /summary internal UInt64 ullAvailPhys; /// summary /// 系统或当前进程的当前已提交内存限制以字节为单位以较小者为准。要获得系统范围的承诺内存限制请调用GetPerformanceInfo /// /summary internal UInt64 ullTotalPageFile; /// summary /// 当前进程可以提交的最大内存量以字节为单位。该值等于或小于系统范围的可用提交值。要计算整个系统的可承诺值调用GetPerformanceInfo核减价值CommitTotal从价值CommitLimit /// /summary internal UInt64 ullAvailPageFile; /// summary /// 调用进程的虚拟地址空间的用户模式部分的大小以字节为单位。该值取决于进程类型、处理器类型和操作系统的配置。例如对于 x86 处理器上的大多数 32 位进程此值约为 2 GB对于在启用4 GB 调整的系统上运行的具有大地址感知能力的 32 位进程约为 3 GB 。 /// /summary internal UInt64 ullTotalVirtual; /// summary /// 当前在调用进程的虚拟地址空间的用户模式部分中未保留和未提交的内存量以字节为单位 /// /summary internal UInt64 ullAvailVirtual; /// summary /// 预订的。该值始终为 0 /// /summary internal UInt64 ullAvailExtendedVirtual; internal void Refresh() { dwLength checked((UInt32)Marshal.SizeOf(typeof(MemoryStatusExE))); }}定义引用库函数的入口public static partial class Native{/// summary /// 检索有关系统当前使用物理和虚拟内存的信息 /// /summary /// param namelpBuffer/param /// returns/returns [LibraryImport(Kernel32.dll, SetLastError true)] [return: MarshalAs(UnmanagedType.Bool)] internal static partial Boolean GlobalMemoryStatusEx(ref MemoryStatusExE lpBuffer);}然后调用 Kernel32.dll 中的函数public class Program{static void Main(){var result GetValue();Console.WriteLine($“当前实际可用内存量{result.ullAvailPhys / 1000 / 1000}MB”);Console.ReadKey();}/// exception crefWin32Exception/exception public static MemoryStatusExE GetValue() { var memoryStatusEx new MemoryStatusExE(); // 重新初始化结构的大小 memoryStatusEx.Refresh(); // 刷新值 if (!Native.GlobalMemoryStatusEx(ref memoryStatusEx)) throw new Win32Exception(无法获得内存信息); return memoryStatusEx; }}使用 AOT 发布项目执行 CsharpAot.exe 文件。image-20221109202709566减少体积在前面两个例子中可以看到 CsharpAot.exe 文件大约在 3MB 左右但是这个文件还是太大了那么我们如何进一步减少 AOT 文件的大小呢读者可以从这里了解如何裁剪程序https://learn.microsoft.com/zh-cn/dotnet/core/deploying/trimming/trim-self-contained需要注意的是裁剪是没有那么简单的里面配置繁多有一些选项不能同时使用每个选项又能带来什么样的效果这些选项可能会让开发者用得很迷茫。经过笔者的大量测试笔者选用了以下一些配置能够达到很好的裁剪效果供读者测试。首先引入一个库ItemGroup PackageReference IncludeMicrosoft.DotNet.ILCompiler Version7.0.0-* / /ItemGroup接着在项目文件中加入以下选项!--AOT 相关-- PublishAottrue/PublishAot TrimModefull/TrimMode RunAOTCompilationTrue/RunAOTCompilation PublishTrimmedtrue/PublishTrimmed TrimmerRemoveSymbolstrue/TrimmerRemoveSymbols PublishReadyToRunEmitSymbolsfalse/PublishReadyToRunEmitSymbols DebuggerSupportfalse/DebuggerSupport EnableUnsafeUTF7Encodingtrue/EnableUnsafeUTF7Encoding InvariantGlobalizationtrue/InvariantGlobalization HttpActivityPropagationSupportfalse/HttpActivityPropagationSupport MetadataUpdaterSupporttrue/MetadataUpdaterSupport UseSystemResourceKeystrue/UseSystemResourceKeys IlcDisableReflection true/IlcDisableReflection最后发布项目。吃惊生成的可执行文件只有 1MB 了而且还可以正常执行。image-20221109203013246笔者注虽然现在看起来 AOT 的文件很小了但是如果使用到 HttpClient、System.Text.Json 等库哪怕只用到了一两个函数最终包含这些库以及这些库使用到的依赖生成的 AOT 文件会大得惊人。所以如果项目中使用到其他 nuget 包的时候别想着生成的 AOT 能小多少C# 导出函数这一步可以从时总的博客中学习更多https://www.cnblogs.com/InCerry/p/CSharp-Dll-Export.htmlPS时总真的太强了。image-20221109235629370在 C 语言中导出一个函数的格式可以这样// MyCFuncs.h#ifdef __cplusplusextern “C” { // only need to export C interface if// used by C source code#endif__declspec( dllimport ) void MyCFunc();__declspec( dllimport ) void AnotherCFunc();#ifdef __cplusplus}#endif当代码编译之后我们就可以通过引用生成的库文件调用 MyCFunc、AnotherCFunc 两个方法。如果不导出的话别的程序是无法调用库文件里面的函数。因为 .NET 7 的 AOT 做了很多改进因此.NET 程序也可以导出函数了。新建一个项目名字就叫 CsharpExport 吧我们接下来就在这里项目中编写我们的动态链接库。添加一个 CsharpExport.cs 文件内容如下using System.Runtime.InteropServices;namespace CsharpExport{public class Export{[UnmanagedCallersOnly(EntryPoint “Add”)]public static int Add(int a, int b){return a b;}}}然后在 .csproj 文件中加上 PublishAot 选项。image-20221109203907544然后通过以下命令发布项目生成链接库dotnet publish -p:NativeLibShared -r win-x64 -c Releaseimage-20221109204002557看起来还是比较大为了继续裁剪体积我们可以在 CsharpExport.csproj 中加入以下配置以便生成更小的可执行文件。!--AOT 相关-- PublishAottrue/PublishAot TrimModefull/TrimMode RunAOTCompilationTrue/RunAOTCompilation PublishTrimmedtrue/PublishTrimmed TrimmerRemoveSymbolstrue/TrimmerRemoveSymbols PublishReadyToRunEmitSymbolsfalse/PublishReadyToRunEmitSymbols DebuggerSupportfalse/DebuggerSupport EnableUnsafeUTF7Encodingtrue/EnableUnsafeUTF7Encoding InvariantGlobalizationtrue/InvariantGlobalization HttpActivityPropagationSupportfalse/HttpActivityPropagationSupport MetadataUpdaterSupporttrue/MetadataUpdaterSupport UseSystemResourceKeystrue/UseSystemResourceKeys IlcDisableReflection true/IlcDisableReflectionimage-20221109204055118C# 调用 C# 生成的 AOT在本小节中将使用 CsharpAot 项目调用 CsharpExport 生成的动态链接库。把 CsharpExport.dll 复制到 CsharpAot 项目中并配置 始终复制。image-20221109204210638在 CsharpAot 的 Native 中加上[LibraryImport(CsharpExport.dll, SetLastError true)] [return: MarshalAs(UnmanagedType.I4)] internal static partial Int32 Add(Int32 a, Int32 b);image-20221109204443706

相关新闻

AI编程工具工程优化与架构设计实战

AI编程工具工程优化与架构设计实战

1. AI产品竞争的本质:从Codex技术架构看决胜关键 第一次接触Codex这类AI编程工具时,大多数开发者都会被其强大的代码生成能力震撼。但真正深入使用后会发现,同类工具在基础功能上往往相差无几——都能理解自然语言指令、都能生成可运行代码、…

2026/7/23 9:58:17阅读更多 →
C语言实现Go通道:并发安全队列的设计与避坑指南

C语言实现Go通道:并发安全队列的设计与避坑指南

1. 项目概述:为什么要在C里再造Go的通道?如果你像我一样,长期在嵌入式、高性能计算或者需要与底层硬件、遗留C库打交道的领域工作,那么对Go语言那个简洁优雅的channel(通道)一定又爱又恨。爱的是它“通过通…

2026/7/23 9:58:17阅读更多 →
Open Deep Research:LangChain 官方开源深度研究 Agent 的设计逻辑与实践价值

Open Deep Research:LangChain 官方开源深度研究 Agent 的设计逻辑与实践价值

现在我有了足够的信息,开始撰写完整的中文学习笔记。 Open Deep Research:LangChain 官方开源深度研究 Agent 的设计逻辑与实践价值 核心观点 这不是一个"又一个搜索增强 LLM"的工具。Open Deep Research 的真正价值在于它是一个公开可复现的…

2026/7/23 9:58:17阅读更多 →
AI论文助手:智能降重与语言优化的核心技术解析

AI论文助手:智能降重与语言优化的核心技术解析

1. 项目概述:AI论文助手的核心价值解析"爱毕业aibiye的AI论文助手"是一款面向学术写作场景的智能工具,其核心功能聚焦于两大刚需:智能降重与语言优化。在当前的学术环境下,论文原创性检测标准日益严格,传统人…

2026/7/23 17:26:45阅读更多 →
Gemini 3\.5 Flash Cyber实战教程:AI自动化漏洞挖掘部署与代码安全审计落地

Gemini 3\.5 Flash Cyber实战教程:AI自动化漏洞挖掘部署与代码安全审计落地

前言 网络安全行业长期存在一个无解的底层矛盾:人工安全审计的迭代速度,永远追不上代码迭代和漏洞爆发的速度。大型互联网企业、政企单位的代码仓库日均提交数千次变更,开源依赖库每周更新数十个版本,传统人工渗透测试、静态代码扫…

2026/7/23 17:26:45阅读更多 →
在Ubuntu 18.04(实体机)上配置OpenWRT的开发环境

在Ubuntu 18.04(实体机)上配置OpenWRT的开发环境

广西河池学院 广西高校重点实验室培训基地 系统控制与信息处理重点实验室 本篇博客来自河池学院:OpenWRT无线路由组 写作时间:2020年7月28日20:26:40 在Ubuntu 18.04(实体机)上配置OpenWRT的开发环境 一、安装虚拟机(实…

2026/7/23 17:26:45阅读更多 →
2026网安避坑深度科普:哪些技术没必要深学?哪些技能学了直接过时?

2026网安避坑深度科普:哪些技术没必要深学?哪些技能学了直接过时?

📌 核心看点 网安行业技术迭代极快,每年都有大量技术淘汰、大量课程过时。 很多新人盲目跟风学习,耗费大量时间学即将淘汰、毫无就业价值、实战无法落地的技术,白白浪费数月甚至数年时间。 本文超长深度盘点2026年没必要深学、…

2026/7/23 17:26:45阅读更多 →
国家科学技术奖名单公布!医学领域获奖汇总

国家科学技术奖名单公布!医学领域获奖汇总

2026年7月8日,国家科学技术奖励大会、两院院士大会、中国科协第十一次全国代表大会在京召开。2025年度国家科学技术奖揭晓。2025年度国家科学技术奖共评选出258个项目和11名科技专家。其中医学领域有30个获奖项目。名单如下:数据来源:&#x…

2026/7/23 17:26:45阅读更多 →
2026年瓷砖行业主流品牌汇总,十大品牌、一线品牌有哪些?

2026年瓷砖行业主流品牌汇总,十大品牌、一线品牌有哪些?

在家装装修过程中,瓷砖是地面、墙面铺装的核心主材,直接影响家居空间的整体颜值、使用体验与居住质感。消费者在挑选瓷砖时,通常会重点关注品牌综合实力、产品生产工艺、品质稳定性、环保等级以及配套服务等核心要素。2026年,瓷砖…

2026/7/23 17:24:45阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/23 0:56:31阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/23 0:56:31阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 0:56:31阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:00:28阅读更多 →
从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…

2026/7/23 0:00:28阅读更多 →
油泥处理设备哪里能买到

油泥处理设备哪里能买到

油泥处理设备哪里有?这是许多从事油田、炼化、清罐业务的从业者最关心的问题。根据河南三丰环保设备有限公司的行业经验,选购油泥处理设备的核心在于设备能否适配当地环保法规与原料特性,而非单纯看价格。该公司总经理王钦田先生指出&#xf…

2026/7/23 0:00:28阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/22 22:56:18阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/22 18:55:50阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/22 18:55:50阅读更多 →