diff --git a/README.md b/README.md index 5a50874..539f0ec 100644 --- a/README.md +++ b/README.md @@ -660,7 +660,6 @@ Hello LUA! The following example was contributed by [@r9y9](https://github.com/r9y9). It shows how to invoke exported Go functions from the Julia language. As [documented here](https://docs.julialang.org/en/stable/manual/calling-c-and-fortran-code/), Julia has the capabilities to invoke exported functions from shared libraries similar to other languages discussed here. File [client.jl](./client.jl) - ```julia struct GoSlice arr::Ptr{Void} @@ -703,7 +702,6 @@ Hello from Julia! The following example was contributed by @dpurfield. It shows how to invoke exported Go functions from the Dart language. As documented [here](https://dart.dev/guides/libraries/c-interop), Dart has the capability to invoke exported functions from shared libraries similar to other languages discussed here. File [client.dart](./client.dart) - ```dart import 'dart:convert'; import 'dart:ffi'; @@ -815,6 +813,84 @@ void main(List args) { stdin.readByteSync(); } ``` +## From C# +To call the exported Go functions from C# we use the [DllImportAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportattribute?view=netframework-4.8) attribute to dynamically load and call exported Go functions in the awesome.so shared object file as shown in the following snippet. + +File [client.cs](./client.cs) +```cs +using System; +using System.Runtime.InteropServices; + +class Awesome +{ + const string libName = "awesome.so"; + + public struct GoSlice + { + public IntPtr data; + public long len, cap; + public GoSlice(IntPtr data, long len, long cap) + { + this.data = data; + this.len = len; + this.cap = cap; + } + } + public struct GoString + { + public string msg; + public long len; + public GoString(string msg, long len) + { + this.msg = msg; + this.len = len; + } + } + + // Use DllImport to import the Awesome lib. + [DllImport(libName)] + public static extern int Add(long a, long b); + + [DllImport(libName)] + public static extern double Cosine(double a); + + [DllImport(libName)] + public static extern void Sort(GoSlice a); + + [DllImport(libName, CharSet = CharSet.Unicode)] + public static extern void Log(GoString msg); + + static void Main() + { + long add = Add(12, 99); + double cosine = Cosine(1); + + long[] data = { 77, 12, 5, 99, 28, 23 }; + IntPtr data_ptr = Marshal.AllocHGlobal(Buffer.ByteLength(data)); + Marshal.Copy(data, 0, data_ptr, data.Length); + var nums = new GoSlice(data_ptr, data.Length, data.Length); + Sort(nums); + Marshal.Copy(nums.data, data, 0, data.Length); + + string msg = "Hello from C#!"; + GoString str = new GoString(msg, msg.Length); + + Console.WriteLine("awesome.Add(12,99) = " + add); + Console.WriteLine("awesome.Cosine(1) = " + cosine); + Console.WriteLine("awesome.Sort(77,12,5,99,28,23): " + string.Join(", ", data)); + Log(str); + } +} +``` +When the example is executed, it produces the following: + +``` +> dotnet run +awesome.Add(12,99) = 111 +awesome.Cosine(1) = 0,5403023058681398 +awesome.Sort(77,12,5,99,28,23): 5, 12, 23, 28, 77, 99 +Hello from C#! +``` ## Conclusion This repo shows how to create a Go library that can be used from C, Python, Ruby, Node, Java, Lua, Julia. By compiling Go packages into C-style shared libraries, Go programmers have a powerful way of integrating their code with any modern language that supports dynamic loading and linking of shared object files. diff --git a/client.cs b/client.cs new file mode 100644 index 0000000..5001ce3 --- /dev/null +++ b/client.cs @@ -0,0 +1,63 @@ +using System; +using System.Runtime.InteropServices; + +class Awesome +{ + const string libName = "awesome.so"; + + public struct GoSlice + { + public IntPtr data; + public long len, cap; + public GoSlice(IntPtr data, long len, long cap) + { + this.data = data; + this.len = len; + this.cap = cap; + } + } + public struct GoString + { + public string msg; + public long len; + public GoString(string msg, long len) + { + this.msg = msg; + this.len = len; + } + } + + // Use DllImport to import the Awesome lib. + [DllImport(libName)] + public static extern int Add(long a, long b); + + [DllImport(libName)] + public static extern double Cosine(double a); + + [DllImport(libName)] + public static extern void Sort(GoSlice a); + + [DllImport(libName, CharSet = CharSet.Unicode)] + public static extern void Log(GoString msg); + + static void Main() + { + long add = Add(12, 99); + double cosine = Cosine(1); + + long[] data = { 77, 12, 5, 99, 28, 23 }; + IntPtr data_ptr = Marshal.AllocHGlobal(Buffer.ByteLength(data)); + Marshal.Copy(data, 0, data_ptr, data.Length); + var nums = new GoSlice(data_ptr, data.Length, data.Length); + Sort(nums); + Marshal.Copy(nums.data, data, 0, data.Length); + + string msg = "Hello from C#!"; + GoString str = new GoString(msg, msg.Length); + + Console.WriteLine("awesome.Add(12,99) = " + add); + Console.WriteLine("awesome.Cosine(1) = " + cosine); + Console.WriteLine("awesome.Sort(77,12,5,99,28,23): " + string.Join(", ", data)); + Log(str); + } +}