Как передать динамический список из IronPython в C#

#python #c# #ironpython #dynamic-language-runtime

Вопрос:

Я хочу, чтобы приложение на python передавало общий список в мой код на C#. Я создал демонстрационное приложение, которое дублирует проблему, которую я вижу.

У меня есть этот код python (Python 2.7) MainApp.py , который вызывает библиотеку DLL C# (.NET 4.7):

 import clr, sys

sys.path.append(r"C:PathToMyProjectClassLibrary1binDebug")
clr.AddReference(r"C:PathToMyProjectClassLibrary1binDebugClassLibrary1.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(список имен): Ни один метод не соответствует заданным аргументам для sayHello: (<тип «список»>)

Ответ №1:

Я решил эту проблему с помощью следующего кода:

MainApp.py:

 import clr, sys

sys.path.append(r"C:ProjectstempClassLibrary1binDebug")
clr.AddReference(r"C:ProjectstempClassLibrary1binDebugClassLibrary1.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)
 

Класс 1.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)
 

Это исправило ошибку типа, но я начал получать новое сообщение:

Необработанное исключение: Система.Отражение.Исключение TargetInvocationException: Исключение было вызвано целью вызова. —> Система.Исключение AccessViolationException: Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена.
на Python.Время выполнения.Время выполнения.PyObject_GetAttrString(указатель IntPtr, имя строки) в Python.Время выполнения.ПиОбъект.GetAttr(имя строки) в Python.Время выполнения.ПиОбъект.TryGetMember(связыватель GetMemberBinder, объект и результат) на сайте вызова.Цель(Закрытие , место вызова , объект ) в Системе.Динамический.Обновленыелегаты.UpdateAndExecute1[T0,TRet](сайт сайта вызова, T0 arg0) в ClassLibrary1.Class1.sayHello(Имена объектов []) в C:Projectscsharp-nine-cookbookcsharp-nine-cookbookCSharp9CookbookClassLibrary1Class1.cs:line 11 — Конец трассировки внутреннего стека исключений — в System.RuntimeMethodHandle.Вызов метода(Цель объекта, аргументы объекта [], Сигнатура sig, логический конструктор) в Системе.Отражение.RuntimeMethodInfo.UnsafeInvokeInternal(Объект obj, параметры объекта [], аргументы объекта []) в системе.Отражение.RuntimeMethodInfo.Вызов(Object obj, BindingFlags invokeAttr, Связующее связующее, параметры объекта [], культура CultureInfo)
на Python.Время выполнения.Переплетчик методов.Вызовите(IntPtr inst, IntPtr args, IntPtr kw, информация о базе методов, методинфо[] методинфо) на Python.Время выполнения.Методобъект.Вызовите(цель IntPtr, аргументы IntPtr, параметры IntPtr, информация о базе методов) в Python.Время выполнения.Привязка метода.tp_call(IntPtr ob, IntPtr args, IntPtr kw)

Очевидно, IronPython не позволил мне передавать пользовательские типы с python на C#. Чтобы исправить это, я добавил Person класс в код C# :

 public class Person
{
    public Person(string name)
    {
        Name = name;
    }

    public string Name { get; set; }
}
 

Затем я удалил пользовательский класс Person из кода python и сослался на него в коде C# :

 from ClassLibrary1 import Person
 

После этого все работало нормально.