问题描述
我想要一个 python 应用程序将一个通用列表传递给我的 C# 代码。我创建了一个演示应用程序,它复制了我所看到的问题。
我有这个调用 C# DLL (.NET 4.7) 的 Python 代码 (Python 2.7) MainApp.py
:
import clr,sys
sys.path.append(r"C:\PathToMyProject\ClassLibrary1\bin\Debug")
clr.AddReference(r"C:\PathToMyProject\ClassLibrary1\bin\Debug\ClassLibrary1.dll")
from ClassLibrary1 import Class1
class Person:
def __init__(self,Name):
self.Name = Name
myclass = Class1()
nameList = []
nameList.append(Person("Joe"))
nameList.append(Person("Mary"))
nameList.append(Person("Chris"))
result = myclass.SayHello(nameList)
print(result)
请注意,我有一个 Person
对象的列表,nameList
,我正在尝试传递这些对象。这是 C# 代码:
using System.Collections.Generic;
namespace ClassLibrary1
{
public class Class1
{
public string SayHello(List<dynamic> names)
{
return $"Hello,{names.Count} people!";
}
}
}
SayHello
方法接受 List<dynamic>
的参数。但是,我在运行 >python MainApp.py
时收到以下错误:
回溯(最近一次调用最后一次):文件“.\MainApp.py”,第 20 行,在
结果 = myclass.SayHello(nameList) TypeError:没有方法匹配 SayHello 的给定参数:(
解决方法
我用下面的代码解决了这个问题:
MainApp.py:
import clr,sys
sys.path.append(r"C:\Projects\temp\ClassLibrary1\bin\Debug")
clr.AddReference(r"C:\Projects\temp\ClassLibrary1\bin\Debug\ClassLibrary1.dll")
from ClassLibrary1 import Class1
from ClassLibrary1 import Person
myclass = Class1()
nameList = []
nameList.append(Person("Joe"))
nameList.append(Person("Mary"))
nameList.append(Person("Chris"))
result = myclass.SayHello(nameList)
print(result)
Class1.cs:
namespace ClassLibrary1
{
public class Class1
{
public string SayHello(dynamic[] names)
{
foreach (var item in names)
{
System.Console.WriteLine(item.Name);
}
return $"Hello,{names.Length} people!";
}
}
public class Person
{
public Person(string name)
{
Name = name;
}
public string Name { get; set; }
}
}
我做的第一件事是将 SayHello
参数类型从 List<dynamic>
更改为 dynamic[]
。
public string SayHello(dynamic[] names)
修复了类型错误,但我开始收到一条新消息:
未处理的异常:System.Reflection.TargetInvocationException:
调用的目标已抛出异常。 --->
System.AccessViolationException:试图读取或写入保护
记忆。这通常表明其他内存已损坏。
在 Python.Runtime.Runtime.PyObject_GetAttrString(IntPtr 指针,
字符串名称) 在 Python.Runtime.PyObject.GetAttr(String name) 在
Python.Runtime.PyObject.TryGetMember(GetMemberBinder binder,Object&
结果)在 CallSite.Target(Closure,CallSite,Object ) 处
System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite
站点,T0 arg0) 在 ClassLibrary1.Class1.SayHello(Object[] names) 中
C:\Projects\csharp-nine-cookbook\csharp-nine-cookbook\CSharp9Cookbook\ClassLibrary1\Class1.cs:line
11 --- 内部异常堆栈跟踪结束 --- 在
System.RuntimeMethodHandle.InvokeMethod(Object target,Object[]
参数、签名 sig、布尔构造函数)在
System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj,Object[] 参数,Object[] 参数)在
System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags
invokeAttr、Binder 绑定器、Object[] 参数、CultureInfo 文化)
在 Python.Runtime.MethodBinder.Invoke(IntPtr inst,IntPtr args,IntPtr
kw,MethodBase 信息,MethodInfo[] methodinfo) at
Python.Runtime.MethodObject.Invoke(IntPtr target,IntPtr
kw,MethodBase 信息)在 Python.Runtime.MethodBinding.tp_call(IntPtr
ob,IntPtr kw)
显然 IronPython 不允许我将自定义类型从 python 传递到 C#。为了解决这个问题,我在 C# 代码中添加了一个 Person
类:
public class Person
{
public Person(string name)
{
Name = name;
}
public string Name { get; set; }
}
然后我从 python 代码中删除了自定义 Person 类并在 C# 代码中引用了那个:
from ClassLibrary1 import Person
之后一切正常。