ç®å½
- èæ¯
- C# é¨å
- ç¯å¢è¦æ±
- å建ä¸ä¸ªæ§å¶å°é¡¹ç®
- ä½éª AOT ç¼è¯
- C# è°ç¨åºå½æ°
- åå°ä½ç§¯
- C# 导åºå½æ°
- C# è°ç¨ C# çæç AOT
- Golang é¨å
- å®è£ GCC
- Golang 导åºå½æ°
- .NET C# å Golang äºè°
- C# è°ç¨ Golang
- Golang è°ç¨ C#
- å ¶ä»
èæ¯
å ¶å®ï¼è§åè¿ç¯æç« æä¸æ®µæ¶é´äºï¼ä½æ¯æ¯è¾æï¼æä»¥ä¸ç´æç没åã
æè¿æ¶æ»æ´æ°å¤ªå¿«äºï¼å¤ªå·äºï¼æä»¥åç .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ã
IDEï¼Visual Studio 2022
Desktop development with C++ workload
æ¯ä¸ä¸ªå·¥å ·éï¼éé¢å å« C++ å¼åå·¥å ·ï¼éè¦å¨
Visual Studio Installer
ä¸å®è£ ï¼å¦ä¸å¾çº¢æ¡ä¸æç¤ºã
å建ä¸ä¸ªæ§å¶å°é¡¹ç®
é¦å å建ä¸ä¸ª .NET 7 æ§å¶å°é¡¹ç®ï¼å称为
CsharpAot
ã
æå¼é¡¹ç®ä¹åï¼åºæ¬ä»£ç å¦å¾æç¤ºï¼
æä»¬ä½¿ç¨ä¸é¢ç代ç åæµè¯ï¼
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 模å¼ï¼éè¦å¨é¡¹ç®æä»¶ä¸å ä¸
<PublishAot>true</PublishAot>
é项ã
ç¶åä½¿ç¨ Visual Studio åå¸é¡¹ç®ã
åå¸é¡¹ç®çé ç½®æä»¶è®¾ç½®ï¼éè¦æç §ä¸å¾è¿è¡é ç½®ã
AOT è· çæå个æä»¶
两个é项ä¸è½åæ¶ä½¿ç¨ï¼å 为 AOT æ¬èº«å°±æ¯å个æä»¶ã
é ç½®å®æåï¼ç¹å»
åå¸
ï¼ç¶åæå¼
Release
ç®å½ï¼ä¼çå°å¦å¾æç¤ºçæä»¶ã
.exe
æ¯ç¬ç«ç坿§è¡æä»¶ï¼ä¸éè¦åä¾èµ
.NET Runtime
ç¯å¢ï¼è¿ä¸ªç¨åºå¯ä»¥æ¾å°å ¶ä»æ²¡æå®è£ .NET ç¯å¢çæºå¨ä¸è¿è¡ã
ç¶åå é¤ä»¥ä¸ä¸ä¸ªæä»¶ï¼
CsharpAot.exp CsharpAot.lib CsharpAot.pdb
å
ç¨ .exe
å³å¯è¿è¡ï¼å
¶ä»æ¯è°è¯ç¬¦å·çæä»¶ï¼ä¸æ¯å¿
éçã
å©ä¸
CsharpAot.exe
æä»¶åï¼å¯å¨è¿ä¸ªç¨åºï¼
C# è°ç¨åºå½æ°
è¿ä¸é¨åç代ç 示ä¾ï¼æ¯ä»ç¬è çä¸ä¸ªå¼æºé¡¹ç®ä¸æ½ååºæ¥çï¼è¿ä¸ªé¡¹ç®å°è£ äºä¸äºè·åç³»ç»èµæºçæ¥å£ï¼ä»¥åå¿«éæ¥å ¥ 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
{
/// <summary>
/// ç»æç大å°ï¼ä»¥åè为åä½ï¼å¿
é¡»å¨è°ç¨ GlobalMemoryStatusEx ä¹åè®¾ç½®æ¤æåï¼å¯ä»¥ç¨ Init æ¹æ³æåå¤ç
/// </summary>
/// <remarks>åºå½ä½¿ç¨æ¬å¯¹è±¡æä¾ç Init ï¼è䏿¯ä½¿ç¨æé 彿°ï¼</remarks>
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 name="lpBuffer"></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 cref="Win32Exception"></exception> public static MemoryStatusExE GetValue { var memoryStatusEx = new MemoryStatusExE; // éæ°åå§åç»æçå¤§å° memoryStatusEx.Refresh; // å·æ°å¼ if (!Native.GlobalMemoryStatusEx(ref memoryStatusEx)) throw new Win32Exception("æ æ³è·å¾å
åä¿¡æ¯"); return memoryStatusEx; } }
ä½¿ç¨ AOT åå¸é¡¹ç®ï¼æ§è¡
CsharpAot.exe
æä»¶ã
åå°ä½ç§¯
å¨åé¢ä¸¤ä¸ªä¾åä¸å¯ä»¥çå°
CsharpAot.exe
æä»¶å¤§çº¦å¨ 3MB å·¦å³ï¼ä½æ¯è¿ä¸ªæä»¶è¿æ¯å¤ªå¤§äºï¼é£ä¹æä»¬å¦ä½è¿ä¸æ¥åå° AOT æä»¶ç大å°å¢ï¼
读è å¯ä»¥ä»è¿éäºè§£å¦ä½è£åªç¨åºï¼https://learn.microsoft.com/zh-cn/dotnet/core/deploying/trimming/trim-self-contained
éè¦æ³¨æçæ¯ï¼è£åªæ¯æ²¡æé£ä¹ç®åçï¼éé¢é ç½®ç¹å¤ï¼æä¸äºé项ä¸è½åæ¶ä½¿ç¨ï¼æ¯ä¸ªé项åè½å¸¦æ¥ä»ä¹æ ·çææï¼è¿äºé项å¯è½ä¼è®©å¼åè ç¨å¾å¾è¿·è«ã
ç»è¿ç¬è ç大鿵è¯ï¼ç¬è éç¨äºä»¥ä¸ä¸äºé ç½®ï¼è½å¤è¾¾å°å¾å¥½çè£åªææï¼ä¾è¯»è æµè¯ã
é¦å ï¼å¼å ¥ä¸ä¸ªåºï¼
<ItemGroup> <PackageReference Include="Microsoft.DotNet.ILCompiler" Version="7.0.0-*" /> </ItemGroup>
æ¥çï¼å¨é¡¹ç®æä»¶ä¸å å ¥ä»¥ä¸é项ï¼
<!--AOT ç¸å
³--> <PublishAot>true</PublishAot> <TrimMode>full</TrimMode> <RunAOTCompilation>True</RunAOTCompilation> <PublishTrimmed>true</PublishTrimmed> <TrimmerRemoveSymbols>true</TrimmerRemoveSymbols> <PublishReadyToRunEmitSymbols>false</PublishReadyToRunEmitSymbols> <DebuggerSupport>false</DebuggerSupport> <EnableUnsafeUTF7Encoding>true</EnableUnsafeUTF7Encoding> <InvariantGlobalization>true</InvariantGlobalization> <HttpActivityPropagationSupport>false</HttpActivityPropagationSupport> <MetadataUpdaterSupport>true</MetadataUpdaterSupport> <UseSystemResourceKeys>true</UseSystemResourceKeys> <IlcDisableReflection >true</IlcDisableReflection>
æåï¼åå¸é¡¹ç®ã
åæï¼çæç坿§è¡æä»¶åªæ 1MB äºï¼èä¸è¿å¯ä»¥æ£å¸¸æ§è¡ã
ç¬è 注ï¼è½ç¶ç°å¨çèµ·æ¥ AOT çæä»¶å¾å°äºï¼ä½æ¯å¦æä½¿ç¨å°
HttpClient
ã
System.Text.Json
çåºï¼åªæåªç¨å°äºä¸ä¸¤ä¸ªå½æ°ï¼æç»å å«è¿äºåºä»¥åè¿äºåºä½¿ç¨å°çä¾èµï¼çæç AOT æä»¶ä¼å¤§å¾æäººã
æä»¥ï¼å¦æé¡¹ç®ä¸ä½¿ç¨å°å ¶ä» nuget å çæ¶åï¼å«æ³ççæç AOT è½å°å¤å°ï¼
C# 导åºå½æ°
è¿ä¸æ¥å¯ä»¥ä»æ¶æ»çå客ä¸å¦ä¹ æ´å¤ï¼https://www.cnblogs.com/InCerry/p/CSharp-Dll-Export.html
PSï¼æ¶æ»çç太强äºã![]()
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用
å¨ C è¯è¨ä¸ï¼å¯¼åºä¸ä¸ªå½æ°çæ ¼å¼å¯ä»¥è¿æ ·ï¼
// MyCFuncs.h #ifdef __cplusplus extern "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
é项ã
ç¶åéè¿ä»¥ä¸å½ä»¤åå¸é¡¹ç®ï¼çæé¾æ¥åºï¼
dotnet publish -p:NativeLib=Shared -r win-x64 -c Release
çèµ·æ¥è¿æ¯æ¯è¾å¤§ï¼ä¸ºäºç»§ç»è£åªä½ç§¯ï¼æä»¬å¯ä»¥å¨
CsharpExport.csproj
ä¸å å ¥ä»¥ä¸é ç½®ï¼ä»¥ä¾¿çææ´å°ç坿§è¡æä»¶ã
<!--AOT ç¸å
³--> <PublishAot>true</PublishAot> <TrimMode>full</TrimMode> <RunAOTCompilation>True</RunAOTCompilation> <PublishTrimmed>true</PublishTrimmed> <TrimmerRemoveSymbols>true</TrimmerRemoveSymbols> <PublishReadyToRunEmitSymbols>false</PublishReadyToRunEmitSymbols> <DebuggerSupport>false</DebuggerSupport> <EnableUnsafeUTF7Encoding>true</EnableUnsafeUTF7Encoding> <InvariantGlobalization>true</InvariantGlobalization> <HttpActivityPropagationSupport>false</HttpActivityPropagationSupport> <MetadataUpdaterSupport>true</MetadataUpdaterSupport> <UseSystemResourceKeys>true</UseSystemResourceKeys> <IlcDisableReflection >true</IlcDisableReflection>
C# è°ç¨ C# çæç AOT
卿¬å°èä¸ï¼å°ä½¿ç¨
CsharpAot
项ç®è°ç¨
CsharpExport
çæç卿龿¥åºã
æ
CsharpExport.dll
å¤å¶å°
CsharpAot
项ç®ä¸ï¼å¹¶é ç½®å§ç»å¤å¶ã
å¨
CsharpAot
ç
Native
ä¸å ä¸ï¼
[LibraryImport("CsharpExport.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.I4)] internal static partial Int32 Add(Int32 a, Int32 b);
ç¶åå¨ä»£ç ä¸ä½¿ç¨ï¼
static void Main { var result = Native.Add(1, 2); Console.WriteLine($"1 + 2 = {result}"); Console.ReadKey; }
å¨ Visual Studio éå¯å¨ Debug è°è¯ï¼
å¯ä»¥çå°ï¼æ¯æ£å¸¸è¿è¡çã
æ¥çï¼å°
CsharpAot
项ç®åå¸ä¸º AOT åï¼å次æ§è¡ï¼
å¯ä»¥çå°ï¼.NET AOT è°ç¨ .NET AOT çä»£ç æ¯æ²¡æé®é¢çã
Golang é¨å
Go çæ Windows 卿龿¥åºï¼éè¦å®è£ GCCï¼éè¿ GCC ç¼è¯ä»£ç çæå¯¹åºå¹³å°çæä»¶ã
å®è£ GCC
éè¦å®è£ GCC 10.3ï¼å¦æ GCC çæ¬å¤ªæ°ï¼ä¼å¯¼è´ç¼è¯ Go 代ç 失败ã
æå¼ tdm-gcc å®ç½ï¼éè¿æ¤å·¥å ·å®è£ GCCï¼å®ç½å°åï¼
https://jmeubank.github.io/tdm-gcc/download/
ä¸è½½åï¼æ ¹æ®æç¤ºå®è£ ã
ç¶åæ·»å ç¯å¢åéï¼
D:\TDM-GCC-64\bin
è¿è¡
gcc -v
ï¼æ£æ¥æ¯å¦å®è£ æåï¼ä»¥åçæ¬æ¯å¦æ£ç¡®ã
Golang 导åºå½æ°
æ¬èçç¥è¯ç¹æ¯ cgoï¼è¯»è å¯ä»¥ä»è¿éäºè§£æ´å¤ï¼
https://www.programmerall.com/article/11511112290/
æ°å»ºä¸ä¸ª Go 项ç®ï¼
æ°å»ºä¸ä¸ª
main.go
æä»¶ï¼æä»¶å 容å¦ä¸ï¼
package main import ( "fmt" ) import "C" //export Start func Start(arg string) { fmt.Println(arg) } // 没ç¨å¤ func main { }
å¨ Golang ä¸ï¼è¦å¯¼åºæ¤æä»¶ä¸ç彿°ï¼éè¦å ä¸
import "C"
ï¼å¹¶ä¸
import "C"
éè¦ä½¿ç¨ç¬ç«ä¸è¡æ¾ç½®ã
//export {彿°åç§°}
表示è¦å¯¼åºç彿°ï¼æ³¨æï¼
//
å
export
ä¹é´ 没æç©ºæ ¼ã
å°
main.go
ç¼è¯ä¸ºå¨æé¾æ¥åºï¼
go build -ldflags "-s -w" -o main.dll -buildmode=c-shared main.go
ä¸å¾ä¸è¯´ï¼Go ç¼è¯åºçæä»¶ï¼ç¡®å®æ¯ .NET AOT å°ä¸äºã
åé¢ï¼ç¬è æ¼ç¤ºäº .NET AOT è°ç¨ .NET AOT ï¼é£ä¹ï¼ Go è°ç¨ Go æ¯å¦å¯ä»¥å¢ï¼
çæ¡æ¯ï¼ä¸å¯ä»¥ã
å 为 Go ç¼è¯åºæ¥ç 卿龿¥åºæ¬èº«å¸¦æ runtimeï¼Go è°ç¨
main.dll
æ¶ ï¼ä¼åºç°å¼å¸¸ã
å ·ææ åµå¯ä»¥éè¿ Go 宿¹ä»åºç Issue äºè§£ï¼https://github.com/golang/go/issues/22192
è¿ä¸ªæ¶åï¼.NET å
1
åã
è½ç¶ Go ä¸è½è°ç¨ Go çï¼ä½æ¯ Go å¯ä»¥è°ç¨ .NET çãå¨æç« åé¢ä¼ä»ç»ã
è½ç¶è¯´ Go ä¸è½è°ç¨èªå·±ï¼è¿éè¿æ¯ç»§ç»è¡¥å ¨ä»£ç ï¼è¿ä¸æ¥æ¼ç¤ºä¸ä¸ã
Go éè¿å¨æé¾æ¥åºè°ç¨å½æ°ç示ä¾ï¼
func main { maindll := syscall.NewLazyDLL("main.dll") start := maindll.NewProc("Start") var v string = "æµè¯ä»£ç " var ptr uintptr = uintptr(unsafe.Pointer(&v)) start.Call(ptr) }
ä»£ç æ§è¡å伿¥éï¼
.NET C# å Golang äºè°
C# è°ç¨ Golang
å°
main.dll
æä»¶å¤å¶æ¾å°
CsharpAot
项ç®ä¸ï¼è®¾ç½®å§ç»å¤å¶ã
ç¶åå¨
Native
䏿·»å 以ä¸ä»£ç ï¼
[LibraryImport("main.dll", SetLastError = true)] internal static partial void Start(IntPtr arg);
è°ç¨
main.dll
ä¸ç彿°ï¼
static void Main { string arg = "让 Go è·èµ·æ¥"; // å°ç³è¯·éæç®¡å
åstring转æ¢ä¸ºæé IntPtr concatPointer = Marshal.StringToHGlobalAnsi(arg); Native.Start(concatPointer); Console.ReadKey; }
å¨ .NET ä¸ string æ¯å¼ç¨ç±»åï¼èå¨ Go è¯è¨ä¸ string æ¯å¼ç±»åï¼è¿ä¸ªä»£ç æ§è¡åï¼ä¼åºç°ä»ä¹ç»æå¢ï¼
æ§è¡ç»ææ¯è¾åºä¸ä¸ªé¿æ°åã
ç¬è ä¸å¤ªäºè§£ Golang å é¨çåçï¼ä¸ç¡®å®è¿ä¸ªæ°åæ¯ä¸æ¯ .NET string ä¼ éäºæéå°åï¼ç¶å Go ææéå°åå½å符串æå°åºæ¥äºã
å ä¸ºå¨ CãGoã.NET çè¯è¨ä¸ï¼å ³äº charãstring çå é¨å¤çæ¹å¼ä¸ä¸æ ·ï¼å æ¤è¿éçä¼ éæ¹å¼å¯¼è´äºè·æä»¬çé¢æç»æä¸ä¸æ ·ã
æ¥çï¼æä»¬å°
main.go
æä»¶ç
Start
彿°æ¹æï¼
//export Start func Start(a,b int) int{ return a+b }
ç¶åæ§è¡å½ä»¤éæ°çæå¨æé¾æ¥åºï¼
go build -ldflags "-s -w" -o main.dll -buildmode=c-shared main.go
å°
main.dll
æä»¶ å¤å¶å°
CsharpAot
项ç®ä¸ï¼å°
Start
彿°å¼ç¨æ¹æï¼
[LibraryImport("main.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.I4)] internal static partial Int32 Start(int a, int b);
æ§è¡ä»£ç è°ç¨
Start
彿°ï¼
static void Main { var result = Native.Start(1, 2); Console.WriteLine($"1 + 2 = {result}"); Console.ReadKey; }
Golang è°ç¨ C#
å°
CsharpExport.dll
æä»¶å¤å¶æ¾å° Go 项ç®ä¸ã
å°
main
çä»£ç æ¹æï¼
func main { maindll := syscall.NewLazyDLL("CsharpExport.dll") start := maindll.NewProc("Add") var a uintptr = uintptr(1) var b uintptr = uintptr(2) result, _, _ := start.Call(a, b) fmt.Println(result) }
å°åæ°æ¹æ
1
ã
9
ï¼å次æ§è¡ï¼
å ¶ä»
卿¬æä¸ï¼ç¬è æ¼ç¤ºäº .NET AOTï¼è½ç¶ç®åç示ä¾çèµ·æ¥æ¯æ£å¸¸çï¼ä½ç§¯ä¹è¶³å¤å°ï¼ä½æ¯å¦æå å ¥äºå®é ä¸å¡ä¸éè¦ç代ç ï¼æç»çæç AOT æä»¶ä¹æ¯å¾å¤§çã
ä¾å¦ï¼é¡¹ç®ä¸ä½¿ç¨
HttpClient
è¿ä¸ªåºï¼ä¼åç°éé¢å å ¥äºå¤§éçä¾èµæä»¶ï¼å¯¼è´çæç AOT æä»¶å¾å¤§ã
å¨ .NET çåºä¸ï¼å¾å¤æ¶å设计äºå¤§éçéè½½ï¼åä¸ä¸ªä»£ç æå¥½å 个åç§æ¹å¼ï¼ä»¥å彿°çè°ç¨é¾å¤ªé¿ï¼è¿æ ·ä¼è®©çæç AOT æä»¶å徿¯è¾èè¿ã
ç®åæ¥è¯´ï¼ ASP.NET Core è¿ä¸æ¯æ AOTï¼è¿ä¹æ¯ä¸ä¸ªé®é¢ã
å¨ C# é¨åï¼æ¼ç¤ºäºå¦æä½¿ç¨ C# è°ç¨ç³»ç»æ¥å£ï¼è¿é读è å¯ä»¥äºè§£ä¸ä¸
pinvoke
ï¼http://pinvoke.net/
è¿ä¸ªåºå°è£ 好äºç³»ç»æ¥å£ï¼å¼åè ä¸éè¦èªå·±æ¸ä¸éï¼éè¿è¿ä¸ªåºå¯ä»¥å¾è½»æ¾å°è°ç¨ç³»ç»æ¥å£ï¼ä¾å¦ç¬è æè¿å¨å MAUI 项ç®ï¼éè¿ Win32 API æ§å¶æ¡é¢çªå£ï¼éé¢å°±ä½¿ç¨å°
pinvoke
ç®åäºå¤§é代ç ã
æ¬ææ¯ç¬è ç¬å¤åçï¼æ¯è¾èµ¶ï¼éäºæ°´å¹³ï¼æä¸å¯è½ä¼æé误çå°æ¹ï¼æå¤§ä½¬ä¸åææã