Why C# Doesn't Live in a Vacuum, and How It Works
\n\nWhen I started working with C# about ten years ago, it seemed to me that .NET was a self-sufficient universe. Libraries, frameworks, databases — everything at hand. But then a task came up: I needed to use an old C++ library for signal processing. And then I realized — C# integration with other languages is not a luxury, but a necessity for any serious project.
\n\nToday, C# is a cross-platform language with a rich ecosystem, but it can't do everything. Sometimes you need to run a Python script for machine learning, sometimes you need to call a native function from Rust for maximum performance, and sometimes you need to embed a JavaScript engine for dynamic UI generation. The good news: C# can be friends with almost everyone.
\n\nIn this article, I will show real scenarios of C# interaction with other languages with working code, benchmarks, and pitfalls. Let's go!
\n\nP/Invoke: The Classic for C and C++
\n\nPlatform Invocation Services (P/Invoke) is a built-in .NET mechanism for calling functions from native DLLs. It appeared in the first version of .NET and remains the fastest way to integrate with C/C++ code.
\n\nBasic Example: Calling a Function from C
\n\nSuppose we have a native library math_helper.dll with a function:
// math_helper.h\nextern "C" __declspec(dllexport) double calculate_power(double base, int exp);\n\nIn C#, we connect it like this:
\n\nusing System.Runtime.InteropServices;\n\npublic class NativeMath\n{\n [DllImport("math_helper.dll", CallingConvention = CallingConvention.Cdecl)]\n public static extern double calculate_power(double base, int exp);\n}\n\n// Usage\ndouble result = NativeMath.calculate_power(2.0, 10);\nConsole.WriteLine($"2^10 = {result}"); // 1024\n\nImportant points for P/Invoke C#:
\n- \n
- Always specify
CallingConvention— most oftenCdeclorStdCall. \n - For strings, use
MarshalAs(UnmanagedType.LPStr)orLPWStr. \n - Pass structures by reference using
reforout. \n
P/Invoke provides minimal overhead — literally a few nanoseconds per call. If you need to integrate C# with C++ for high-load computations, this is your choice.
\n\nC++/CLI: The Bridge Between Worlds
\n\nC++/CLI is a Visual C++ extension that allows you to write code that works in both managed (.NET) and unmanaged environments. It's not a separate language, but a hybrid often used to create wrappers around C++ libraries.
\n\nExample Wrapper for OpenCV
\n\nSuppose we have a C++ function that processes an image:
\n\n// NativeImageProcessor.h\n#pragma once\npublic ref class ImageProcessor\n{\npublic:\n static System::Drawing::Bitmap^ ApplyFilter(System::Drawing::Bitmap^ bmp);\n};\n\nInside, we call native OpenCV, and externally we return a managed Bitmap. From C#, we use it like a regular .NET library:
using ImageProcessorLib;\n\nvar img = new Bitmap("photo.jpg");\nvar processed = ImageProcessor.ApplyFilter(img);\nprocessed.Save("filtered.jpg");\n\nC++/CLI integration gives full control over memory and avoids marshaling. The downside is that the code becomes platform-dependent and harder to debug.
\n\nPython.NET: Calling Python from C#
\n\nPython is the king of Data Science and machine learning. And if your C# project requires, say, running a neural network on PyTorch or processing text via spaCy, calling Python from C# via Python.NET is what you need.
\n\nInstallation and First Example
\n\nInstall the package:
\n\ndotnet add package Python.Runtime.NETStandardBlogs
Book Recommendations
Read also