【发布时间】:2013-12-28 14:46:29
【问题描述】:
相当精通 C# 和 Python(但对新功能一无所知 dynamic .NET 4.x 中的功能),我最近决定添加 IronPython对我的一个 C# 应用程序的脚本支持。我已经完成了所有基本的通信工作,例如将Action<>s 传入并从 Python 调用到我的 C# 代码中。
但是我在使用 C# 代码中的 python 生成器查找文档或示例时遇到了麻烦。我有一个解决方案,但它远非优雅。
我在我的 python 代码(“test.py”)中定义了一个生成器:
def do_yield():
yield 1
yield 2
yield 3
在 C# 中,我设置了 IronPython 环境:
// set up IronPython
var ipy = Python.CreateRuntime();
test = ipy.UseFile("test.py");
我已经定义了一个辅助函数来将返回的 PythonGenerator 转换为 C# 迭代器,所以我的 foreach 看起来像:
foreach (int n in PythonGeneratorToCSharpIterator<int>(test.do_yield()))
{
Log("py gen returned: " + n);
}
还有我的辅助函数:
IEnumerable<T> PythonGeneratorToCSharpIterator<T>(IronPython.Runtime.PythonGenerator pyGenerator)
{
while (true) {
T t = default(T);
try {
// get the next value
object o = pyGenerator.next();
// will throw an exception if it's not the correct type (or no more values in the generator)
t = (T)o;
}
catch (Exception ex) {
break; // break out of the while loop and return from the iterator
}
yield return t; // this can't be inside try/catch
}
}
当没有更多值要返回时,python 生成器返回一个LightException,因此t = (T)o 行将抛出异常,因为它试图将其转换为int。
这样做的一个问题是我没有捕获并正确处理来自 python 代码的任何异常。我只是把它们扔掉并退出循环。另一个是当我没有来自生成器的值时抛出异常,我更喜欢布尔检查来测试返回的值是否无效。
也许是我对 .NET 的新 dynamic 方面的无知使我无法理解如何正确编码。在 C#/IronPython 中是否有更好/更标准的编码方式?
编辑
来自vcsjones'的评论,我现在有了这段代码,使用Linq 的Cast 扩展方法对我很有效:
var gen = (IronPython.Runtime.PythonGenerator)test.do_yield();
foreach(int n in gen.Cast<int>()) {
Log("py gen returned (with Cast): " + n);
}
【问题讨论】:
-
According to the source 一个 python 生成器已经实现了
IEnumerable<object>,所以你所要做的就是使用 Linq 的Cast<T>。
标签: c# .net iterator generator ironpython