我正在尝试使用C#的DynamicObject为Qt的类系统实现一个通用的Wrapper-Class。但是,我想写下面的代码:
dynamic obj = new SomeWrapperClass(....); // This extends DynamicObject
obj.OnMyEvent += (Action)(() => Console.WriteLine("DO something!"));
以上是根据VS2010的有效代码(需要显式转换为Action),但是我如何使用DynamicObject的方法“捕获”该语句?
我尝试实现TryGetMember()并调用该语句,但我不知道我必须返回什么才能使它工作。
任何提示?
答案 0 :(得分:2)
Reflector是你的朋友。为第二行生成的代码看起来像这样(大约):
if(Binder.IsEvent("OnMyEvent", typeof(SomeWrapperClass)))
{
Binder.InvokeMember("add_OnMyEvent", obj, myAction);
}
else
{
var e = Binder.GetMember("OnMyEvent", obj);
var ae = Binder.BinaryOperation(ExpressionType.AddAssign, e, myAction);
Binder.SetMember("OnMyEvent", obj, ae);
}
如果你不能为OnMyEvent
使用真实事件(在这种情况下你可以依靠默认的DynamicObject
实现),那么你需要返回一些实现AddAssign
的东西返回类似多播委托的东西。如果可能的话,我会建议前者......
为了好玩,这是一个将OnMyEvent动态绑定到OnMyOtherEvent的hackish示例:
public class SomeWrapperClass : DynamicObject
{
public event Action OnMyOtherEvent;
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (binder.Name == "OnMyEvent")
{
result = OnMyOtherEvent;
return true;
}
return base.TryGetMember(binder, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (binder.Name == "OnMyEvent" && value is Action)
{
OnMyOtherEvent = (Action)value;
return true;
}
return TrySetMember(binder, value);
}
public void Test()
{
if (OnMyOtherEvent != null)
OnMyOtherEvent();
}
private static void TestEventHandling()
{
dynamic obj = new SomeWrapperClass(); // This extends DynamicObject
obj.OnMyEvent += (Action)(() => Console.WriteLine("DO something!"));
obj.Test();
}
}
答案 1 :(得分:0)
使用反射调用Action
:
dynamic o = new SomeWrapperClass();
o.OnMyEvent += (Action)(() => Console.WriteLine("DO something!"));
var a = typeof(SomeWrapperClass).GetField("OnMyEvent", BindingFlags.Instance | BindingFlags.NonPublic);
(a.GetValue(o) as Action).Invoke();
输出: 做点什么!
答案 2 :(得分:0)
我认为你与代表们混淆了一些事件。事件是有效的委托,但你不能使用'add'和'remove'访问者与委托 - 但+ =和 - =对两者都一样。
obj.OnMyEvent += (Action)(() => Console.WriteLine("DO something!"));
这基本上是将一个目标添加到委托的调用列表中,因此委托必须具有相似的类型(在这种情况下是无参数的Action委托)。
建议的实施如下:
private Action actiondelegate = (Action)(() => {});
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (binder.Name == "OnMyEvent")
{
result = actiondelegate;
return true;
}
}
请注意,您需要在Action委托中使用空的Action - 这是因为如果它为null,TryGetMember
和TrySetMember
将无法正常工作。