我正在开发一个用C#编写的托管IronPython的应用程序。我计划的是用户将编写python脚本,其中包含实现预定义接口的类。
类似的东西:
用C#代码定义接口:
public interface IPlugin
{
void DoSomething();
}
用python代码实现接口。
class Plugin(IPlugin):
def DoSomething():
print "Doing stuff."
在我的应用程序中,我加载python脚本并执行这些脚本中的类实现的方法。
我想知道:如何获取python脚本中实现指定接口的所有类的句柄?
例如:如果我要在C#中完成所有工作,我会有反思来帮助我,我可以加载程序集并执行以下操作:
Assembly assembly = Assembly.LoadFrom("plugin.dll");
Type[] types = assembly.GetTypes();
foreach(Type type in types)
{
foreach(Type interfaceType in type.GetInterface())
{
if(interfaceType == typeof(IPlugin))
{
// gotcha, invoke interface specific methods
}
}
}
我如何做同样的事情,而不是集会,我正在处理IronPython脚本?我知道使用ObjectOperations和ScriptScope,我可以获得该类的句柄,如果我知道它的名字 - as described here - 但我正在寻找更强大的东西。
答案 0 :(得分:3)
您遇到的问题是IronPython类不是.NET类。 Python类比C#类更具动态性,因此IronPython类通常是.NET对象。
当您在IronPython中继承.NET接口时,它 创建一个新的.NET类,但是多个Python类实际上将共享一个支持.NET类(将只创建一个.NET类用于在IronPython中子类化的每个.NET类型。)
执行此操作的正确方法是使用Python内省来收集IronPython类对象,并使用工厂函数(可以将其用作委托 - 将返回的实例强制转换为接口),您需要在其中实例化它们。 / p>
例如,您可以尝试在Python范围内执行:
list_of_classes = IPlugin.\_\_subclasses_\_
答案 1 :(得分:1)
动态语言通常不使用接口,您正在以非常静态的方式思考:)
不应该担心它是否与某个预定义的接口相匹配,你应该只调用成员函数并处理抛出的任何异常 - 无论如何你都必须处理错误,只需要“不适合方法调用我们期待“再多一点。在Objective-C中,这将被称为“非正式协议”。
答案 2 :(得分:1)
通过调用clr.GetClrType
,您始终可以获得Python类型的支持.NET类型Python.GetClrModule(engine)返回clr模块,然后在其上调用GetClrType方法,传递使用objectoperations获取的Python类。这应该会给你一个System.Type。之后,像往常一样使用GetInterfaces方法。
答案 3 :(得分:0)
根据IronPython常见问题解答,它不支持将* .py文件编译到可以链接到的程序集中:
http://ironpython.codeplex.com/Wiki/View.aspx?title=FAQ&referringTitle=Home
但保罗是正确的,如果您要使用动态语言来实现这种可扩展性,那么您只需要编辑文件,而不必了解运行时的接口。
如果要向系统管理员类型公开此扩展点,则可能需要考虑托管PowerShell。我刚才写了一篇关于如何做到的帖子:
http://notgartner.wordpress.com/2008/02/23/how-to-host-the-powershell-runtime/
PowerShell很有用,因为它已经在使用Exchange的环境中得到了一些采用。请注意 - 我是PowerShell的粉丝,所以请一点点盐:)