C#与其他语言的集成:从P/Invoke到Python和JavaScript

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么C#不孤立存在,以及它是如何工作的

\n\n

大约十年前我开始使用C#时,曾以为.NET是一个自给自足的宇宙。库、框架、数据库——一切尽在掌握。但后来遇到一个任务:需要使用一个旧的C++库来处理信号。这时我意识到——C#与其他语言的集成不是一种奢侈,而是任何严肃项目的必需品。

\n\n

如今,C#是一种拥有丰富生态系统的跨平台语言,但它并不能做到一切。有时需要运行Python脚本进行机器学习,有时需要调用Rust的原生函数以获得最大性能,有时还需要嵌入JavaScript引擎来动态生成UI。好消息是:C#几乎能与所有语言友好协作。

\n\n

在本文中,我将展示C#与其他语言交互的真实场景,包含可运行的代码、基准测试和潜在陷阱。我们开始吧!

\n\n

P/Invoke:C和C++的经典方式

\n\n

平台调用服务(P/Invoke)是.NET内置的机制,用于调用原生DLL中的函数。它自.NET第一个版本就存在,并且仍然是集成C/C++代码最快的方式。

\n\n

基本示例:从C调用函数

\n\n

假设我们有一个原生库 math_helper.dll,其中包含函数:

\n\n
// math_helper.h\nextern "C" __declspec(dllexport) double calculate_power(double base, int exp);
\n\n

在C#中,我们这样引入它:

\n\n
using 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// 使用\ndouble result = NativeMath.calculate_power(2.0, 10);\nConsole.WriteLine($"2^10 = {result}"); // 1024
\n\n

C# P/Invoke的重要事项:

\n
    \n
  • 始终指定 CallingConvention——通常是 Cdecl 或 StdCall。
  • \n
  • 对于字符串,使用 MarshalAs(UnmanagedType.LPStr) 或 LPWStr。
  • \n
  • 通过 ref 或 out 按引用传递结构体。
  • \n
\n\n

P/Invoke的开销极小——每次调用仅需几纳秒。如果您需要将C#与C++集成进行高负载计算,这是您的选择。

\n\n

C++/CLI:连接两个世界的桥梁

\n\n

C++/CLI是Visual C++的一个扩展,允许编写在托管(.NET)和非托管环境中都能运行的代码。它不是一种独立的语言,而是一种混合体,常用于为C++库创建包装器。

\n\n

OpenCV的包装器示例

\n\n

假设我们有一个处理图像的C++函数:

\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\n

在内部,我们调用原生OpenCV,对外则返回托管的 Bitmap。从C#中使用它就像使用普通的.NET库一样:

\n\n
using ImageProcessorLib;\n\nvar img = new Bitmap("photo.jpg");\nvar processed = ImageProcessor.ApplyFilter(img);\nprocessed.Save("filtered.jpg");
\n\n

C++/CLI集成提供了对内存的完全控制,并避免了封送处理。缺点是代码变得平台相关且更难调试。

\n\n

Python.NET:从C#调用Python

\n\n

Python是数据科学和机器学习的王者。如果您的C#项目需要运行PyTorch的神经网络或通过spaCy处理文本,那么通过Python.NET从C#调用Python正是您所需要的。

\n\n

安装和第一个示例

\n\n

安装包:

\n\n
dotnet add package Python.Runtime.NETStandard

博客

书籍推荐