用IronPython对象替换.NET对象实例

时间:2014-03-13 11:45:53

标签: c# python ironpython

我试图执行以下操作:

  • 获取C#中定义的对象的实例
    • 它实现了某个接口
    • 这是另一个C#类实例
    • 上的字段
  • 使用记录方法调用的IronPython代理对象包装它
  • 将包装器放回原位对象

这是一个展示我想要做的事情的例子。实际上,IWoof接口上有更多方法。

C#类和接口:

namespace Foo
{
    public interface IWoof { string DoSomething(); }

    public class Bar
    {
        public Bar() { Woof = new WoofImp(); }
        public IWoof Woof { get; set; }
    }

    public class WoofImp : IWoof
    {
        public string DoSomething()
        {
            return "DoSomething executing in C#";
        }
    }

}

我想使用bar.Woof并将其替换为IronPython代理。我想从IronPython脚本中做到这一点。我尝试过各种各样的事情。

首次尝试:覆盖 getattr

我定义了一个像这样的包装器:

class Wrapper(object):

    def __init__(self, obj):
        self._obj = obj

    def __getattr__(self, name):
        print '__getattr__ called'
        if name == "DoSomething":
           return self.__DoSomething
        else:
            return object.__getattr__(self, name)

    def __DoSomething(self):
        result = self._obj.DoSomething()
        return result + " AND DoSomething executing in Python"

这正常,正如您所期望的那样:

import Foo
bar = Foo.Bar()
woof = Wrapper(bar.Woof)
print woof.DoSomething()

> DoSomething executing in C# AND DoSomething executing in Python

但是,当我尝试用包装对象替换bar.Woof时,它不起作用:

bar.Woof = woof_wrapper

> TypeError: expected IWoof, got Object_1$1
> Microsoft.Scripting.ArgumentTypeException: expected IWoof, got Object_1$1
   at CallSite.Target(Closure , CallSite , Object , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
   at Microsoft.Scripting.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)

第二次尝试:实现C#接口

显然我的包装器需要实现IWoof接口,所以我试过了。

class Wrapper_IWoof(object, Foo.IWoof): # Inherits from IWoof
... etc

现在我可以添加包装器实例并尝试像这样调用它:

woof = Wrapper_IWoof(bar.Woof)
bar.Woof = woof
print bar.Woof.DoSomething()

但是我遇到了一个新问题:

> AttributeError: 'Wrapper_IWoof' object has no attribute 'DoSomething'
> System.MissingMemberException: 'Wrapper_IWoof' object has no attribute 'DoSomething'
   at IronPython.Runtime.Operations.PythonOps.MissingInvokeMethodException(Object o, String name)
   at IronPython.NewTypes.System.Object#IWoof_4$4.DoSomething()
   at Microsoft.Scripting.Interpreter.FuncCallInstruction`2.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.LightLambda.Run3[T0,T1,T2,TRet](T0 arg0, T1 arg1, T2 arg2)
   at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
   at Microsoft.Scripting.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)

第三次和第四次尝试:动态代理

我也尝试过这里描述的这种方法(并再次实现IWoof): http://www.ronnie-midnight-oil.net/2008/11/checking-type-contract-from-ironpython.html 但是,它们导致了上述两次尝试中发现的相同问题。

替代解决方案

解决同一问题的另一种方法是通过反射生成一个python类并使用它。我做到了这一点并且有效。这给了我明确的函数声明,如下面Jeff Hardy所描述的那样。

但是,我真的很想知道上述尝试为什么不起作用。我做错了什么或遗失了什么?

1 个答案:

答案 0 :(得分:0)

我认为你使用__getattr__使事情过于复杂。尝试直接实现界面:

class Wrapper_IWoof(object, Foo.IWoof):

    def __init__(self, obj):
        self._obj = obj

    def DoSomething(self):
        result = self._obj.DoSomething()
        return result + " AND DoSomething executing in Python"