3 ms·
Declaring and calling a C method in C# is as trivial as [LibraryImport("my_library", EntryPoint = "pass_numbers")] partial static void PassNumbers(int
by neonsunset 3y ago
Declaring and calling a C method in C# is as trivial as
[LibraryImport("my_library", EntryPoint = "pass_numbers")]
partial static void PassNumbers(int a, int b, int c);
For AOT compilation, you can even completely statically link[0] it into the binary and annotate with [SuppressGCTransition] - it will be as cheap as a direct call from C++ (although GC transition is just a helper stub call that is barely noticeable on microbenchmarks - 1-2ns difference at throughput).
In fact, you can also do the reverse and AOT-compile C# projects to regular dll/libs which can be called from C, C++, Rust, etc. land with ease:
[UnmanagedCallersOnly(EntryPoint = "receive_c_string")]
public unsafe static void ReceiveCString(byte* ptr) { /* impl.. */ }
(there are other aspects that make this a powerful combo like being able to wrap pointers into new Span<byte>(ptr, length)'s and transparently inter-operating with most of the standard library without ever allocating)
Panama may offer better UX but not the one that can match C# and only marginally improves performance over JNI[1] (which is still slow).
[0] https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/interop#linking https://learn.microsoft.com/en-us/dotnet/core/deploying/nati...
[1] https://github.com/Glavo/java-ffi-benchmark https://github.com/Glavo/java-ffi-benchmark