如何将动态列表从 IronPython 传递到 C#

问题描述

我想要一个 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

之后一切正常。