Передача списков от IronPython до С#

Я хочу передать список строк из IronPython 2.6 для .NET 2.0 в программу на С# (я использую .NET 2.0, потому что я работаю с api, который запускает библиотеки DLL, созданные на основе 2.0). Но я не уверен, как отбросить его, поскольку он возвращается из ScriptEngine.

namespace test1
{
    class Program
    {
        static void Main(string[] args)
        {
            ScriptEngine engine = Python.CreateEngine();
            ScriptSource source = engine.CreateScriptSourceFromFile("C:\\File\\Path\\To\\my\\script.py");
            ScriptScope scope = engine.CreateScope();

            ObjectOperations op = engine.Operations;

            source.Execute(scope); // class object created
            object classObject = scope.GetVariable("MyClass"); // get the class object
            object instance = op.Invoke(classObject); // create the instance
            object method = op.GetMember(instance, "myMethod"); // get a method
            List<string> result = (List<string>)op.Invoke(method); // call the method and get result
            Console.WriteLine(result.ToString());
            Console.Read();
        }
    }
}

мой код python имеет класс с методом, который возвращает список строк python:

class MyClass(object):
    def myMethod(self):
        return ['a','list','of','strings']

Я получаю эту ошибку:

Unable to cast object of type 'IronPython.Runtime.List' to type 'System.Collections.Generic.List`1[System.String]'.

Ответы

Ответ 1

IronPython.Runtime.List реализует следующие интерфейсы:

IList, ICollection, IList<object>, ICollection<object>, IEnumerable<object>, IEnumerable

чтобы вы могли применить к одному из этих типов, затем перейдите в List<string>.

List<string> result = ((IList<object>)op.Invoke(method)).Cast<string>().ToList();

Кстати, возможно, вы знаете об этом, но вы также можете использовать .NET-типы в IronPython, например:

from System.Collections.Generic import *

class MyClass(object):
    def myMethod(self):
        return List[str](['a','list','of','strings'])

здесь myMethod возвращает непосредственно a List<string>


EDIT:

Учитывая, что вы используете .net 2.0 (так нет LINQ), у вас есть два варианта (IMO):

1. Вставить в IList<object> и использовать его:

IList<object> result = (IList<object>)op.Invoke(method);

PROs: не требуется цикл, вы будете использовать тот же экземпляр объекта, который возвращается python script.
CONs: нет безопасности типа (вы будете похожи на python, поэтому вы можете добавить в список не строку)

2. Преобразовать в List<string>/IList<string>:

IList<object> originalResult = (IList<object>)op.Invoke(method);
List<string> typeSafeResult = new List<string>();
foreach(object element in originalResult)
{
    typeSafeResult.Add((string)element);
}

PROs: введите безопасный список (вы можете добавить только строки).
CONs: для этого требуется цикл, а преобразованный список - это новый экземпляр (не тот, который был возвращен script)

Ответ 2

Вы можете использовать IList на стороне С#, и IronPython автоматически переносит объект List в оболочку, которая делает конверсии в/из строки при доступе к списку.