Python調(diào)用C# dll的兩種主要方法
Python 調(diào)用 C# DLL 的完整案例
下面提供兩種主要方法:使用 pythonnet (推薦) 和使用 COM 組件。
方法一:使用 pythonnet (clr) - 推薦
1. 創(chuàng)建 C# 類庫項(xiàng)目
MathOperations.cs
using System;
using System.Runtime.InteropServices;
namespace CSharpDLL
{
[ComVisible(true)] // 使類對 COM 可見
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")] // 唯一標(biāo)識(shí)符
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
};
}
// 靜態(tài)方法
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}";
}
}
// 高級(jí)功能示例
[ComVisible(true)]
[Guid("12345678-1234-1234-1234-123456789DEF")]
public class AdvancedOperations
{
// 回調(diào)函數(shù)示例
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 (重要:添加強(qiáng)名和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# 項(xiàng)目
使用 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 調(diào)用 C# DLL 的主程序
"""
import os
import sys
import clr
from typing import List, Dict, Any
import logging
# 設(shè)置日志
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', ''))
# 導(dǎo)入命名空間
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 = {}
# 測試整數(shù)運(yùn)算
results['add'] = self._math_ops.Add(10, 20)
# 測試浮點(diǎn)數(shù)運(yùn)算
results['multiply'] = self._math_ops.Multiply(3.14, 2.5)
# 測試字符串處理
results['greet'] = self._math_ops.Greet("Python")
# 測試數(shù)組處理
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]:
"""測試高級(jí)操作"""
if not self._loaded or not self._advanced_ops:
raise RuntimeError("DLL 未加載")
results = {}
# 測試回調(diào)函數(shù)
def progress_callback(progress, message):
logger.info(f"進(jìn)度回調(diào): {progress}% - {message}")
logger.info("開始測試長時(shí)運(yùn)行操作...")
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():
"""主函數(shù)"""
# DLL 路徑 - 請根據(jù)實(shí)際情況修改
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# 項(xiàng)目生成 DLL 文件")
return
# 創(chuàng)建管理器
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")
# 測試高級(jí)操作
logger.info("=== 測試高級(jí)操作 ===")
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"測試過程中發(fā)生錯(cuò)誤: {e}")
if __name__ == "__main__":
main()
方法二:使用 COM 組件
1. C# COM 組件注冊
修改 C# 項(xiàng)目屬性:
- 在項(xiàng)目屬性中勾選 “Register for COM interop”
- 或者使用 regasm 手動(dòng)注冊:
regasm CSharpDLL.dll /tlb /codebase
2. Python 使用 COM 組件
com_interop.py
#!/usr/bin/env python3
"""
使用 COM 組件方式調(diào)用 C# DLL
"""
import pythoncom
import win32com.client
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def test_com_interop():
"""測試 COM 互操作"""
try:
# 創(chuàng)建 COM 對象
math_ops = win32com.client.Dispatch("CSharpDLL.MathOperations")
# 測試方法調(diào)用
result = math_ops.Add(15, 25)
logger.info(f"15 + 25 = {result}")
result = math_ops.Greet("COM Client")
logger.info(f"Greeting: {result}")
# 測試數(shù)組處理
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()
完整項(xiàng)目結(jié)構(gòu)
CSharpPythonInterop/ ├── CSharpDLL/ # C# 類庫項(xiàng)目 │ ├── MathOperations.cs │ ├── Person.cs │ ├── AdvancedOperations.cs │ ├── AssemblyInfo.cs │ └── CSharpDLL.csproj ├── PythonClient/ # Python 客戶端 │ ├── main.py │ ├── com_interop.py │ ├── install_requirements.py │ └── requirements.txt └── README.md
使用說明
環(huán)境要求
- 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
運(yùn)行測試:
python main.py
注意事項(xiàng)
- 架構(gòu)匹配: 確保 Python 和 C# DLL 的架構(gòu)一致 (x86/x64)
- 依賴項(xiàng): 如果 C# DLL 有依賴項(xiàng),確保它們在同一目錄或 GAC 中
- 異常處理: C# 異常會(huì)作為 Python 異常拋出,需要適當(dāng)處理
- 性能: 對于高頻調(diào)用,考慮批量操作減少互操作開銷
常見問題解決
- DLL 加載失敗: 檢查路徑和依賴項(xiàng)
- 類型轉(zhuǎn)換錯(cuò)誤: 確保參數(shù)類型匹配
- 內(nèi)存泄漏: 及時(shí)釋放 COM 對象
- 線程安全: 在多線程環(huán)境中注意同步
這個(gè)完整案例展示了 Python 調(diào)用 C# DLL 的各種場景,包括基本類型、數(shù)組、對象、回調(diào)、事件和異常處理等。
以上就是Python調(diào)用C# dll的兩種主要方法的詳細(xì)內(nèi)容,更多關(guān)于Python調(diào)用C# dll的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python?datacompy?找出兩個(gè)DataFrames不同的地方
本文主要介紹了Python?datacompy?找出兩個(gè)DataFrames不同的地方,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧<BR>2022-05-05
Python 模擬動(dòng)態(tài)產(chǎn)生字母驗(yàn)證碼圖片功能
這篇文章主要介紹了Python 模擬動(dòng)態(tài)產(chǎn)生字母驗(yàn)證碼圖片,這里給大家介紹了pillow模塊的使用,需要的朋友可以參考下2019-12-12
Python中實(shí)現(xiàn)高效的列表過濾多種方法示例
這篇文章主要給大家介紹了關(guān)于Python中實(shí)現(xiàn)高效的列表過濾的多種方法,包括基礎(chǔ)的for循環(huán)、列表推導(dǎo)式、filter函數(shù)、itertools模塊,以及高級(jí)的pandas和numpy庫,我們還討論了生成器的使用,以及在實(shí)際場景中的應(yīng)用,需要的朋友可以參考下2024-12-12
Python 中l(wèi)ist ,set,dict的大規(guī)模查找效率對比詳解
這篇文章主要介紹了Python 中l(wèi)ist ,set,dict的大規(guī)模查找效率對比詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
PyTorch環(huán)境中CUDA版本沖突問題排查與解決方案
在使用 PyTorch 進(jìn)行深度學(xué)習(xí)開發(fā)時(shí),CUDA 版本兼容性問題是個(gè)老生常談的話題,本文將通過一次真實(shí)的排查過程,剖析 PyTorch 虛擬環(huán)境自帶 CUDA 運(yùn)行時(shí)庫與系統(tǒng)全局 CUDA 環(huán)境沖突的場景,需要的朋友可以參考下2025-02-02
OneFlow源碼解析之Eager模式下Tensor存儲(chǔ)管理
這篇文章主要為大家介紹了OneFlow源碼解析之Eager模式下Tensor的存儲(chǔ)管理實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
python Tkinter版學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了python Tkinter版學(xué)生管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02

