zoukankan      html  css  js  c++  java
  • 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%

    GCC下载:Windows 64位版本  || Windows 32位版本,也可以从从云盘下载
    下载之后,解压后确保 gcc 命令在搜索路径(Path)中。
    更多信息可参考:https://www.cnblogs.com/ghj1976/p/3540257.html

    3. 操作系统 64 位与 32 的编译

    在 LiteIDE 中,可以通过配置 win32.envwin64.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();
    

    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. 相关参考

  • 相关阅读:
    多线程批量插入数据到数据库
    分分钟搞定redis
    Eclipse中JS文件红叉处理
    springmvc基础篇—处理图片静态资源文件
    springmvc基础篇—使用注解方式为前台提供数据
    springmvc基础篇—拆分配置文件
    springmvc基础篇—通过注解的方式去配置项目
    springmvc基础篇—修改默认的配置文件名称及位置
    springmvc基础篇—掌握三种控制器
    springmvc基础篇—掌握三种处理器
  • 原文地址:https://www.cnblogs.com/timeddd/p/11731160.html
Copyright © 2011-2022 走看看