go语言 c# 混合编程 pdf,C# 结合 Golang 开发
1. 實現方式與語法形式
基本方式:將 Go 程序編譯成 DLL 供 C# 調用。
1.1 Go代碼
注意:代碼中 export 的注釋是定義的入口描述不能省略
package main
import "C"
import "fmt"
func main() {
fmt.Println(Test())
}
var _count = 0
//Test :
//export Test
func Test() int {
_count++
return _count
}
在 LiteIDE 中將編譯配置的 BUILDARGS 自定義值為 --buildmode=c-shared -o Test.dll,從而形成以下編譯語句。
go build --buildmode=c-shared -o Test.dll
1.2 C# 代碼
[DllImport("Test.dll", EntryPoint = "Test")]
extern static int Test();
2. Windows 下編譯依賴的環境
生成 DLL 依賴于 gcc,沒有 gcc 環境時,會報以下錯誤:
"gcc": executable file not found in %PATH%
3. 操作系統 64 位與 32 的編譯
在 LiteIDE 中,可以通過配置 win32.env 和 win64.env 來指定不同的 gcc 環境路徑達到生成指定系統的 DLL 文件。
4. c# 中操作系統 64 位與 32 的適配
在 c# 中判斷操作系統是否 64 位,可以使用以下語句。
bool is64 = Environment.Is64BitOperatingSystem;
為了在不同的操作系統下,加載不同的 DLL,采取以下步驟來進行組織。
(1)將 32 位的版本命名為 Test32.dll,將 64 位的版本命名為 Test64.dll
(2)定義 ITest 接口,將 DLL 將要調用的方法定義為接口方法
(3)分別為ITest接口實現 Test32 與 Test64 類,在類中加載相應的 DLL
(4)通過判斷操作系統類型,實例化一個 ITest 的具體實現類實例來使用
具體接口與類實現代碼如下:
public interface ITest
{
int Test();
}
public class Test32 : ITest
{
class TestDLL
{
const string DLL_NAME = "Test32.dll";
[DllImport(DLL_NAME, EntryPoint = "Test")]
public extern static int Test();
}
public int Test()
{
return TestDLL.Test();
}
}
public class Test64 : ITest
{
class TestDLL
{
const string DLL_NAME = "Test64.dll";
[DllImport(DLL_NAME, EntryPoint = "Test")]
public extern static int Test();
}
public int Test()
{
return TestDLL.Test();
}
}
實例化與調用:
ITest test = Environment.Is64BitOperatingSystem ? (ITest)new Test64() : (ITest)new Test32();
int result = test.Test();
還有一種方式:
[DllImport("kernel32")]
private static extern IntPtr LoadLibraryA([MarshalAs(UnmanagedType.LPStr)] string fileName);
-- DllImport 會先在加載的里邊找名稱,可以預先加載。
LoadLibraryA((Environment.Is64BitOperatingSystem ? "x64" : "x86") + "/Test.dll");
補充一下 LoadLibrary 的查找路徑說明
LoadLibrary的查找路徑,可以參見MSDN上的文章:Dynamic-Link Library Search Order。
默認情況如下:
The directory from which the application loaded. (應用程序所在的目錄)
The system directory. Use the GetSystemDirectory function to get the path of this directory. (system32目錄)
The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched. (System目錄)
The Windows directory. Use the GetWindowsDirectory function to get the path of this directory. (Windows目錄)
The current directory. (當前目錄,執行命令的發起目錄)
The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. (PATH路徑)
5. 其它一些問題
5.1 字符串轉換
傳入字符串,C#: byte[] -> GO: *C.char
接收字符串,GO: string -> C#: GoString struct
GO 定義示例
//Hello :
//export Hello
func Hello(name *C.char) string {
return fmt.Sprintf("hello %s", C.GoString(name))
}
C# GoString struct 定義
public struct GoString
{
public IntPtr p;
public int n;
public GoString(IntPtr n1, int n2)
{
p = n1; n = n2;
}
}
C# DllImport 聲明
[DllImport(DLL_NAME, EntryPoint = "Hello", CallingConvention = CallingConvention.Cdecl)]
public extern static GoString Hello(byte[] name);
C# GoString struct 轉 String
public string GoStringToCSharpString(GoString goString)
{
byte[] bytes = new byte[goString.n];
for (int i = 0; i < goString.n; i++)
{
bytes[i] = Marshal.ReadByte(goString.p, i);
}
string result = Encoding.UTF8.GetString(bytes);
return result;
}
C# 調用示例
GoString goResult = test.Hello(Encoding.UTF8.GetBytes("張三"));
Debug.WriteLine(GoStringToCSharpString(goResult));
5.2 調試
CallingConvention
在聲明中加入 CallingConvention = CallingConvention.Cdecl 避免未知異常。
[DllImport("Test.dll", CallingConvention = CallingConvention.Cdecl)]
程序崩潰甚至異常提示都沒有,可在加載 DLL 之前:
Environment.SetEnvironmentVariable("GODEBUG", "cgocheck=0");
6. 相關參考
總結
以上是生活随笔為你收集整理的go语言 c# 混合编程 pdf,C# 结合 Golang 开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql order by按照汉字拼音
- 下一篇: go tcp客户端自动重连_使用 Go