使用新的async/await模型,生成一个Task在事件触发时完成的模型非常简单; 你只需要遵循这种模式:
public class MyClass
{
public event Action OnCompletion;
}
public static Task FromEvent(MyClass obj)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
obj.OnCompletion += () =>
{
tcs.SetResult(null);
};
return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)
这允许:
await FromEvent(new MyClass());
Run Code Online (Sandbox Code Playgroud)
问题是你需要为FromEvent你想要的每个类中的每个事件创建一个新方法await.这可能会变得非常快,而且无论如何它主要只是样板代码.
理想情况下,我希望能够做到这样的事情:
await FromEvent(new MyClass().OnCompletion);
Run Code Online (Sandbox Code Playgroud)
然后我可以FromEvent对任何实例上的任何事件重复使用相同的方法.我花了一些时间来尝试创建这样的方法,并且存在许多障碍.对于上面的代码,它将生成以下错误:
事件'Namespace.MyClass.OnCompletion'只能出现在+ =或 - =的左侧
据我所知,没有办法通过代码传递这样的事件.
所以,下一个最好的事情似乎是尝试将事件名称作为字符串传递:
await FromEvent(new MyClass(), "OnCompletion");
Run Code Online (Sandbox Code Playgroud)
它并不理想; 如果该类型的事件不存在,你就不会得到intellisense并且会遇到运行时错误,但它仍然比大量的FromEvent方法更有用.
因此,使用反射和GetEvent(eventName)获取EventInfo对象很容易.下一个问题是该事件的委托在运行时是未知的(并且需要能够变化).这使得添加事件处理程序变得困难,因为我们需要在运行时动态创建方法,匹配给定签名(但忽略所有参数),访问TaskCompletionSource我们已有的并设置其结果.
幸运的是,我发现此链接包含有关如何[几乎]完全通过的说明Reflection.Emit.现在的问题是我们需要发出IL,我不知道如何访问tcs我拥有的实例.
以下是我为完成此任务所取得的进展:
public static Task …Run Code Online (Sandbox Code Playgroud)