Python调用C# dll的两种主要方法
作者:学亮编程手记
这篇文章主要介绍了两种方法让Python调用C# DLL:推荐的pythonnet方法和使用COM组件的方法,每种方法都有详细的步骤,包括创建和编译C#项目、安装Python依赖、运行测试等,文章还讨论了注意事项,如架构匹配、依赖项、异常处理和性能优化,需要的朋友可以参考下
Python 调用 C# DLL 的完整案例
下面提供两种主要方法:使用 pythonnet (推荐) 和使用 COM 组件。
方法一:使用 pythonnet (clr) - 推荐
1. 创建 C# 类库项目
MathOperations.cs
using System;
using System.Runtime.InteropServices;
namespace CSharpDLL
{
[ComVisible(true)] // 使类对 COM 可见
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")] // 唯一标识符
public interface IMathOperations
{
int Add(int a, int b);
double Multiply(double a, double b);
string Greet(string name);
double[] ProcessArray(double[] numbers);
Person ProcessPerson(Person person);
}
[ComVisible(true)]
[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71")]
[ClassInterface(ClassInterfaceType.None)]
public class MathOperations : IMathOperations
{
public int Add(int a, int b)
{
return a + b;
}
public double Multiply(double a, double b)
{
return a * b;
}
public string Greet(string name)
{
return $"Hello, {name}! from C# DLL";
}
public double[] ProcessArray(double[] numbers)
{
if (numbers == null)
return null;
double[] result = new double[numbers.Length];
for (int i = 0; i < numbers.Length; i++)
{
result[i] = numbers[i] * 2 + 1; // 简单的处理:2*x + 1
}
return result;
}
public Person ProcessPerson(Person person)
{
if (person == null)
return null;
return new Person
{
Name = person.Name.ToUpper(),
Age = person.Age + 1,
Score = person.Score * 1.1
};
}
// 静态方法
public static string GetVersion()
{
return "CSharpDLL v1.0.0";
}
// 重载方法示例
public string ProcessData(string data)
{
return $"Processed string: {data}";
}
public string ProcessData(int data)
{
return $"Processed int: {data}";
}
public string ProcessData(double data)
{
return $"Processed double: {data:F2}";
}
}
[ComVisible(true)]
[Guid("F54F8C0A-69B5-4BC5-9E2A-123456789ABC")]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public double Score { get; set; }
public override string ToString()
{
return $"Person: {Name}, Age: {Age}, Score: {Score}";
}
}
// 高级功能示例
[ComVisible(true)]
[Guid("12345678-1234-1234-1234-123456789DEF")]
public class AdvancedOperations
{
// 回调函数示例
public delegate void ProgressCallback(int progress, string message);
public void LongRunningOperation(ProgressCallback callback)
{
for (int i = 0; i <= 100; i += 10)
{
System.Threading.Thread.Sleep(500);
callback?.Invoke(i, $"Progress: {i}%");
}
}
// 事件示例
public event EventHandler<string> OperationCompleted;
public void StartOperation()
{
System.Threading.Thread.Sleep(1000);
OperationCompleted?.Invoke(this, "Operation completed successfully!");
}
// 异常处理示例
public double SafeDivide(double a, double b)
{
if (b == 0)
throw new DivideByZeroException("Division by zero is not allowed");
return a / b;
}
}
}
AssemblyInfo.cs (重要:添加强名和COM注册信息)
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("CSharpDLL")]
[assembly: AssemblyDescription("C# DLL for Python interop")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CSharpDLL")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(true)]
[assembly: Guid("a13cc3d7-6c1e-4b5a-93a7-2e4c073d7a9a")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
2. 编译 C# 项目
使用 Visual Studio 或命令行编译:
csc /target:library /out:CSharpDLL.dll /reference:System.Runtime.InteropServices.dll *.cs
3. Python 端代码
install_requirements.py
#!/usr/bin/env python3
"""
安装必要的 Python 包
"""
import subprocess
import sys
def install_package(package):
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
if __name__ == "__main__":
packages = ["pythonnet", "clr-loader"]
for package in packages:
try:
print(f"正在安装 {package}...")
install_package(package)
print(f"{package} 安装成功!")
except Exception as e:
print(f"安装 {package} 失败: {e}")
main.py
#!/usr/bin/env python3
"""
Python 调用 C# DLL 的主程序
"""
import os
import sys
import clr
from typing import List, Dict, Any
import logging
# 设置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class CSharpDLLManager:
"""C# DLL 管理器"""
def __init__(self, dll_path: str):
"""
初始化 DLL 管理器
Args:
dll_path: C# DLL 文件路径
"""
self.dll_path = dll_path
self._loaded = False
self._math_ops = None
self._advanced_ops = None
def load_dll(self) -> bool:
"""加载 C# DLL"""
try:
# 添加 DLL 所在目录到 CLR 路径
dll_dir = os.path.dirname(os.path.abspath(self.dll_path))
clr.AddReference(dll_dir)
# 加载 DLL
clr.AddReference(os.path.basename(self.dll_path).replace('.dll', ''))
# 导入命名空间
from CSharpDLL import MathOperations, Person, AdvancedOperations
self._math_ops = MathOperations()
self._advanced_ops = AdvancedOperations()
self._loaded = True
logger.info("C# DLL 加载成功")
return True
except Exception as e:
logger.error(f"加载 C# DLL 失败: {e}")
return False
def test_basic_operations(self) -> Dict[str, Any]:
"""测试基本操作"""
if not self._loaded or not self._math_ops:
raise RuntimeError("DLL 未加载")
results = {}
# 测试整数运算
results['add'] = self._math_ops.Add(10, 20)
# 测试浮点数运算
results['multiply'] = self._math_ops.Multiply(3.14, 2.5)
# 测试字符串处理
results['greet'] = self._math_ops.Greet("Python")
# 测试数组处理
input_array = [1.0, 2.0, 3.0, 4.0, 5.0]
results['array_input'] = input_array
results['array_output'] = list(self._math_ops.ProcessArray(input_array))
# 测试对象处理
person = Person()
person.Name = "Alice"
person.Age = 25
person.Score = 95.5
processed_person = self._math_ops.ProcessPerson(person)
results['person_input'] = str(person)
results['person_output'] = str(processed_person)
# 测试重载方法
results['overload_string'] = self._math_ops.ProcessData("test")
results['overload_int'] = self._math_ops.ProcessData(42)
results['overload_double'] = self._math_ops.ProcessData(3.14159)
return results
def test_advanced_operations(self) -> Dict[str, Any]:
"""测试高级操作"""
if not self._loaded or not self._advanced_ops:
raise RuntimeError("DLL 未加载")
results = {}
# 测试回调函数
def progress_callback(progress, message):
logger.info(f"进度回调: {progress}% - {message}")
logger.info("开始测试长时运行操作...")
self._advanced_ops.LongRunningOperation(progress_callback)
# 测试事件
def operation_completed(sender, args):
logger.info(f"操作完成事件: {args}")
results['event_message'] = args
self._advanced_ops.OperationCompleted += operation_completed
self._advanced_ops.StartOperation()
# 测试异常处理
try:
results['safe_divide_success'] = self._advanced_ops.SafeDivide(10.0, 2.0)
results['safe_divide_error'] = "No error"
except Exception as e:
results['safe_divide_error'] = f"捕获到异常: {e}"
return results
def run_benchmark(self, iterations: int = 10000) -> Dict[str, Any]:
"""性能测试"""
if not self._loaded or not self._math_ops:
raise RuntimeError("DLL 未加载")
import time
start_time = time.time()
for i in range(iterations):
result = self._math_ops.Add(i, i + 1)
end_time = time.time()
return {
'iterations': iterations,
'total_time': end_time - start_time,
'average_time': (end_time - start_time) / iterations * 1000, # 毫秒
'operations_per_second': iterations / (end_time - start_time)
}
def main():
"""主函数"""
# DLL 路径 - 请根据实际情况修改
dll_path = r"CSharpDLL.dll" # 或者完整路径如 r"C:\path\to\CSharpDLL.dll"
if not os.path.exists(dll_path):
logger.error(f"找不到 DLL 文件: {dll_path}")
logger.info("请先编译 C# 项目生成 DLL 文件")
return
# 创建管理器
manager = CSharpDLLManager(dll_path)
# 加载 DLL
if not manager.load_dll():
return
try:
# 测试基本操作
logger.info("=== 测试基本操作 ===")
basic_results = manager.test_basic_operations()
for key, value in basic_results.items():
logger.info(f"{key}: {value}")
print("\n" + "="*50 + "\n")
# 测试高级操作
logger.info("=== 测试高级操作 ===")
advanced_results = manager.test_advanced_operations()
for key, value in advanced_results.items():
logger.info(f"{key}: {value}")
print("\n" + "="*50 + "\n")
# 性能测试
logger.info("=== 性能测试 ===")
benchmark_results = manager.run_benchmark(10000)
for key, value in benchmark_results.items():
logger.info(f"{key}: {value}")
except Exception as e:
logger.error(f"测试过程中发生错误: {e}")
if __name__ == "__main__":
main()
方法二:使用 COM 组件
1. C# COM 组件注册
修改 C# 项目属性:
- 在项目属性中勾选 “Register for COM interop”
- 或者使用 regasm 手动注册:
regasm CSharpDLL.dll /tlb /codebase
2. Python 使用 COM 组件
com_interop.py
#!/usr/bin/env python3
"""
使用 COM 组件方式调用 C# DLL
"""
import pythoncom
import win32com.client
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def test_com_interop():
"""测试 COM 互操作"""
try:
# 创建 COM 对象
math_ops = win32com.client.Dispatch("CSharpDLL.MathOperations")
# 测试方法调用
result = math_ops.Add(15, 25)
logger.info(f"15 + 25 = {result}")
result = math_ops.Greet("COM Client")
logger.info(f"Greeting: {result}")
# 测试数组处理
input_array = [1.0, 2.0, 3.0]
result = math_ops.ProcessArray(input_array)
logger.info(f"Array input: {input_array}")
logger.info(f"Array output: {list(result)}")
except Exception as e:
logger.error(f"COM 互操作失败: {e}")
if __name__ == "__main__":
test_com_interop()
完整项目结构
CSharpPythonInterop/ ├── CSharpDLL/ # C# 类库项目 │ ├── MathOperations.cs │ ├── Person.cs │ ├── AdvancedOperations.cs │ ├── AssemblyInfo.cs │ └── CSharpDLL.csproj ├── PythonClient/ # Python 客户端 │ ├── main.py │ ├── com_interop.py │ ├── install_requirements.py │ └── requirements.txt └── README.md
使用说明
环境要求
- C# 端: .NET Framework 4.7.2+ 或 .NET Core 3.1+/ .NET 5+
- Python 端: Python 3.7+
- 必需包:
pythonnet(推荐) 或pywin32(COM方式)
安装步骤
编译 C# DLL:
cd CSharpDLL dotnet build --configuration Release
安装 Python 依赖:
cd PythonClient pip install pythonnet # 或者 python install_requirements.py
运行测试:
python main.py
注意事项
- 架构匹配: 确保 Python 和 C# DLL 的架构一致 (x86/x64)
- 依赖项: 如果 C# DLL 有依赖项,确保它们在同一目录或 GAC 中
- 异常处理: C# 异常会作为 Python 异常抛出,需要适当处理
- 性能: 对于高频调用,考虑批量操作减少互操作开销
常见问题解决
- DLL 加载失败: 检查路径和依赖项
- 类型转换错误: 确保参数类型匹配
- 内存泄漏: 及时释放 COM 对象
- 线程安全: 在多线程环境中注意同步
这个完整案例展示了 Python 调用 C# DLL 的各种场景,包括基本类型、数组、对象、回调、事件和异常处理等。
以上就是Python调用C# dll的两种主要方法的详细内容,更多关于Python调用C# dll的资料请关注脚本之家其它相关文章!
