是否可以在运行时生成事件处理程序? 我想做那样的事情:
public bool addCallback(string name, Delegate Callback)
{
EventInfo ei = DataProxy.GetType().GetEvent(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (ei == null)
return false;
ei.AddEventHandler(DataProxy, Callback);
//now I want to add an Eventhandler, which removes the Callback and this new Eventhandler itsself
return true;
}
答案 0 :(得分:0)
(我不是100%确定我理解你要将生成的事件处理程序挂钩到示例中,但这是我知道创建事件处理程序的最简单方法)
取决于您的平台和信任级别。最灵活的方法是使用Emit
生成方法(请参阅here)。
然而,我找到了一个相对容易使用且很好的替代方法来生成Linq表达式(这里是namespace help)。
这个想法很简单:
使用您可以在命名空间中看到的各种Expression派生类来定义回调正在执行的操作。在这种情况下,您希望在.RemoveEventHandler
实例上生成调用ei
(我猜)的内容(具体来说,您将使用ConstantExpression为您的{{1}创建引用变量和您的Callback参数以及MethodCallExpression来创建对ei
方法的调用。
创建满足需要的表达式后,需要创建一个委托(Lambda)(参见here)
差不多完成了。您仍然需要编译lambda,通过在上一步(see here)
RemoveDataHandler
来执行此操作
醇>
编辑:这是一个动态生成的委托的Windows控制台示例,用于删除自身。请注意,WP7 Linq表达式支持比.NET 4.0更受限制,因此您需要对其进行调整(制作辅助方法以执行某些工作并从表达式调用它们而不是我所做的)。
Edit2:BTW:lambda可以自行删除的机制是创建另一个返回该类型的局部变量的lambda。创建lambda之后,将它保存到局部变量并运行代码(我不确定这是否可以在没有辅助lambda的情况下工作)
Edit3:不 - 你必须使用委托技巧,否则,常量会被“冻结”,并且不会像你想要的那样更新。因此代码可行。
.Compile
答案 1 :(得分:0)
public static bool addCallback(string name, Delegate Callback)
{
if (DataProxy == null)
GetDataProxy();
EventInfo ei = DataProxy.GetType().GetEvent(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (ei == null)
return false;
ei.AddEventHandler(DataProxy, Callback);
Type handlerType = ei.EventHandlerType;
MethodInfo invokeMethod = handlerType.GetMethod("Invoke");
ParameterInfo[] parms = invokeMethod.GetParameters();
Type[] parmTypes = new Type[parms.Length];
for (int i = 0; i < parms.Length; i++)
{
parmTypes[i] = parms[i].ParameterType;
}
List<ParameterExpression> parameters = new List<ParameterExpression>();
foreach(Type t in parmTypes)
{
parameters.Add(System.Linq.Expressions.Expression.Parameter(t));
}
ConstantExpression eventInfo = System.Linq.Expressions.Expression.Constant(ei, typeof(EventInfo));
ConstantExpression eventCallback = System.Linq.Expressions.Expression.Constant(Callback, typeof(Delegate));
ConstantExpression dataProxy = System.Linq.Expressions.Expression.Constant(DataProxy, typeof(MAServiceClient));
MethodCallExpression call = System.Linq.Expressions.Expression.Call(eventInfo, ei.GetType().GetMethod("RemoveEventHandler"), dataProxy, eventCallback);
//add to Expression.Body the call, which removes the new Eventhandler itsself
ei.AddEventHandler(DataProxy, System.Linq.Expressions.Expression.Lambda(ei.EventHandlerType, call, parameters).Compile());
return true;
}
这就是我的方法现在的样子。只缺少一步,新的Eventhandler(由System.Linq.Expressions.Expression.Lambda(ei.EventHandlerType, call, parameters).Compile()
创建)将自行删除(请参阅注释)。
答案 2 :(得分:0)
感谢Shahar Prish,我想出了以下代码:
using ex = System.Linq.Expressions;
using System.Linq.Expressions;
public static bool addCallback(string name, Delegate Callback)
{
if (DataProxy == null)
GetDataProxy();
EventInfo ei = DataProxy.GetType().GetEvent(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (ei == null)
return false;
ei.AddEventHandler(DataProxy, Callback);
Type handlerType = ei.EventHandlerType;
MethodInfo removeMethod = ei.GetType().GetMethod("RemoveEventHandler");
MethodInfo invokeMethod = handlerType.GetMethod("Invoke");
ParameterInfo[] parms = invokeMethod.GetParameters();
Type[] parmTypes = new Type[parms.Length];
for (int i = 0; i < parms.Length; i++)
{
parmTypes[i] = parms[i].ParameterType;
}
List<ParameterExpression> parameters = new List<ParameterExpression>();
foreach(Type t in parmTypes)
{
parameters.Add(System.Linq.Expressions.Expression.Parameter(t));
}
Delegate self = null;
Func<Delegate> getSelf = () => self;
ConstantExpression eventInfo = ex.Expression.Constant(ei, typeof(EventInfo));
ConstantExpression eventCallback = ex.Expression.Constant(Callback, typeof(Delegate));
ConstantExpression dataProxy = ex.Expression.Constant(DataProxy, typeof(MAServiceClient));
MethodCallExpression removeCallback = ex.Expression.Call(eventInfo, removeMethod, dataProxy, eventCallback);
MethodCallExpression removeSelf = ex.Expression.Call(eventInfo, removeMethod, dataProxy, ex.Expression.Invoke(ex.Expression.Constant(getSelf)));
BlockExpression block = ex.Expression.Block(removeCallback, removeSelf);
LambdaExpression lambda = ex.Expression.Lambda(ei.EventHandlerType, block, parameters);
Delegate del = lambda.Compile();
self = del;
ei.AddEventHandler(DataProxy, del);
lambda = ex.Expression.Lambda(ei.EventHandlerType, block, parameters);
return true;
}
正如我之前所说,此方法应将Eventhandler
传递的Delegate Callback
添加到Event
的名为string name
的{{1}},然后将其删除被调用(以及static MAServiceClient DataProxy
删除了自己的回调)。