从IronPython传递列表到C#

17
我想从IronPython 2.6传递一个字符串列表给.NET 2.0的C#程序(我使用.NET 2.0是因为我要使用基于2.0构建的DLL运行的API)。但是当它从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]'.

你尝试过将结果转换为 IronPython.Runtime.List 吗? - dtb
不行,因为它已经是那种类型了,我想要一个在C#中可以继续使用的System.Collections.Generic.List。 - BenjaminGolder
2个回答

19

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();

顺便提一下,也许你已经知道了,但你也可以在IronPython中使用.NET类型,例如:

from System.Collections.Generic import *

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

这里的myMethod直接返回了一个List<string>


编辑:

考虑到你在使用 .net 2.0(没有LINQ),我认为你有两个选择:

1. 将其转换为IList<object>并使用:

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

优点: 不需要循环,您将使用Python脚本返回的同一对象实例。
缺点: 没有类型安全性(您将像在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);
}

优点: 类型安全的列表(只能添加字符串)。


缺点: 需要循环,并且转换后的列表是一个新实例(而不是脚本返回的相同实例)。


你的建议很有道理,但是当我尝试从IList进行转换时,出现了这个错误:“System.Collections.Generic.IList <object>”不包含“Cast”的定义。我可能错过了一些基础知识。 - BenjaminGolder
针对您关于使用.NET类型的建议,我希望有一些简单的强制转换可以用于基本的Python类型,例如列表、字典和元组,这样我就不必在我的Python脚本中替换为.NET类型(毕竟它是建立在.NET之上的)。也许有一个默认的铁Python类型转换列表。 - BenjaminGolder
@BenjaminGolder:你的.cs头文件中是否包含using System.Linq;?(希望你正在使用.NET 3.5...) - digEmAll
@digEmAll:我需要吗?实际上我正在使用2.0版本,因为我正在使用一个可以从2.0 dlls中工作的api。如果我应该已经知道这些事情,对不起。我对.NET还很新。 - BenjaminGolder
正如我所说的,Python列表被映射为IList<object>,因此如果您想要操作从Python返回的同一对象实例,则必须进行强制转换。否则,您可以将其转换为List<string>(使用循环或LINQ Cast<>),但这当然意味着创建另一个实例。 - digEmAll
显示剩余3条评论

2
你可以在C#端使用IList,IronPython会自动将List对象包装在一个包装器中,访问列表时进行字符串转换。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接