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

4
我想要做以下事情:
1.获取一个C#定义的对象实例 - 它实现了特定的接口 - 它是另一个C#类实例的字段
2.用IronPython代理对象包装它,以记录方法调用
3.把包装器放回原始对象的位置
以下是一个示例,展示了我想要做的事情。实际上,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#";
        }
    }

}

我想用IronPython代理替换bar.Woof。我希望能够从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

我认为你用__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"

我应该明确指出这只是一个玩具示例,用于说明问题。我正在处理的接口有更多的方法,因此我正在寻找一种方法来在不必显式声明每个函数的情况下完成此操作。就像我说的那样,我可以通过代码生成来解决这个问题,它实际上为所有方法执行了您建议的操作。我将编辑问题以澄清。 - Captain Whippet

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