Python调用C#dll的两种主要方法

作者:

文章目录
  • 下面提供两种主要方法:使用 pythonnet (推荐) 和使用 COM 组件。
  • 目录
    • 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方式)

      编译 C# DLL:

      cd CSharpDLL
      dotnet build --configuration Release
      

      安装 Python 依赖:

      cd PythonClient
      pip install pythonnet
      # 或者
      python install_requirements.py
      

      运行测试:

      python main.py
      

      1. 架构匹配: 确保 Python 和 C# DLL 的架构一致 (x86/x64)
      2. 依赖项: 如果 C# DLL 有依赖项,确保它们在同一目录或 GAC 中
      3. 异常处理: C# 异常会作为 Python 异常抛出,需要适当处理
      4. 性能: 对于高频调用,考虑批量操作减少互操作开销

      1. DLL 加载失败: 检查路径和依赖项
      2. 类型转换错误: 确保参数类型匹配
      3. 内存泄漏: 及时释放 COM 对象
      4. 线程安全: 在多线程环境中注意同步

      这个完整案例展示了 Python 调用 C# DLL 的各种场景,包括基本类型、数组、对象、回调、事件和异常处理等。

      以上就是Python调用C# dll的两种主要方法的详细内容,更多关于Python调用C# dll的资料请关注风君子博客其它相关文章!

      您可能感兴趣的文章:

      • 详解Python 调用C# dll库最简方法
      • Python调用C# Com dll组件实战教程
      • C#调用Python脚本程序的两种方法
      • C#使用IronPython调用Python

      站内搜索