文章目录
-
- 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”)]
- 使用 Visual Studio 或命令行编译: csc /target:library /out:CSharpDLL.dll /reference:System.Runtime.InteropServices.dll *.cs
- 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:pathtoCSharpDLL.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()
-
- 修改 C# 项目属性: 在项目属性中勾选 “Register for COM interop” 或者使用 regasm 手动注册: regasm CSharpDLL.dll /tlb /codebase
- 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的资料请关注风君子博客其它相关文章! 您可能感兴趣的文章: 详解Python 调用C# dll库最简方法 Python调用C# Com dll组件实战教程 C#调用Python脚本程序的两种方法 C#使用IronPython调用Python
目录
- Python 调用 C# DLL 的完整案例
- 方法一:使用 pythonnet (clr) – 推荐
- 1. 创建 C# 类库项目
- 2. 编译 C# 项目
- 3. Python 端代码
- 方法二:使用 COM 组件
- 1. C# COM 组件注册
- 2. Python 使用 COM 组件
- 完整项目结构
- 使用说明
- 环境要求
- 安装步骤
- 注意事项
- 常见问题解决
下面提供两种主要方法:使用 pythonnet (推荐) 和使用 COM 组件。
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")]
使用 Visual Studio 或命令行编译:
csc /target:library /out:CSharpDLL.dll /reference:System.Runtime.InteropServices.dll *.cs
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:pathtoCSharpDLL.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()
修改 C# 项目属性:
- 在项目属性中勾选 “Register for COM interop”
- 或者使用 regasm 手动注册:
regasm CSharpDLL.dll /tlb /codebase
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方式)
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的资料请关注风君子博客其它相关文章!
您可能感兴趣的文章:
- 详解Python 调用C# dll库最简方法
- Python调用C# Com dll组件实战教程
- C#调用Python脚本程序的两种方法
- C#使用IronPython调用Python