我想要做以下事情:
1.获取一个C#定义的对象实例 - 它实现了特定的接口 - 它是另一个C#类实例的字段
2.用IronPython代理对象包装它,以记录方法调用
3.把包装器放回原始对象的位置
以下是一个示例,展示了我想要做的事情。实际上,IWoof接口有更多的方法。
C#类和接口:
然而,当我尝试用包装后的对象替换bar.Woof时,它不起作用:
现在我可以添加包装器实例并尝试像这样调用它:
但是我遇到了一个新问题:
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下面所描述的显式函数声明。
但是,我真的很想知道为什么上述尝试不起作用。 我有做错什么或者漏掉了什么吗?