用IronPython对象替换.NET对象实例
我正在尝试做以下几件事:
- 获取一个在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
我觉得你用__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"