在扩展方法中添加事件监听器
add event listener in extension method
在我的主class中,我有这样的事件
private event System.Action OnActionFinished;
并且知道 await 调用 GetAwaiter() 方法,我有 System.Action 扩展方法:
`
public static TaskAwaiter<object> GetAwaiter(this Action action)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
action += () => tcs.SetResult(null);
return tcs.Task.GetAwaiter();
}
为了能够在async
方法中写入await OnActionFinished;
。
public async Task ExecuteTurns(Queue<TurnAction> turnActions)
{
foreach (TurnAction turn in turnActions)
{
Action<Vector2> TurnMethod = null;
switch (turn.TurnType)
{
case TurnType.Walk:
TurnMethod = Walk;
break;
case TurnType.Jump:
TurnMethod = Jump;
break;
case TurnType.Shoot:
TurnMethod = rangedWeapon.Shoot;
break;
}
Task.Run(async () => {
TurnMethod(turn.Direction);
});
await OnActionFinished;
}
}
OnActionFinished 在 Walk、Jump 和 Shoot 方法结束时调用。
为什么这不起作用?
Action
是不可变类型。您没有更改该操作以使其在调用时执行不同的行为,您正在创建一个新操作(然后您什么都不做)来完成您的 TCS。
一般地能够构造一个基于任意事件的 Task
是相当困难的,并且在完全类型安全的情况下完成它是不可能的。 You can see some of the difficulties with doing that here。现在要根据特定对象上的特定事件创建 Task
,当然,这很容易(再次参见之前链接的问题)。
这主要源于 C# 语言本身在事件周围公开的功能,根本不允许这样做。
在我的主class中,我有这样的事件
private event System.Action OnActionFinished;
并且知道 await 调用 GetAwaiter() 方法,我有 System.Action 扩展方法: `
public static TaskAwaiter<object> GetAwaiter(this Action action)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
action += () => tcs.SetResult(null);
return tcs.Task.GetAwaiter();
}
为了能够在async
方法中写入await OnActionFinished;
。
public async Task ExecuteTurns(Queue<TurnAction> turnActions)
{
foreach (TurnAction turn in turnActions)
{
Action<Vector2> TurnMethod = null;
switch (turn.TurnType)
{
case TurnType.Walk:
TurnMethod = Walk;
break;
case TurnType.Jump:
TurnMethod = Jump;
break;
case TurnType.Shoot:
TurnMethod = rangedWeapon.Shoot;
break;
}
Task.Run(async () => {
TurnMethod(turn.Direction);
});
await OnActionFinished;
}
}
OnActionFinished 在 Walk、Jump 和 Shoot 方法结束时调用。
为什么这不起作用?
Action
是不可变类型。您没有更改该操作以使其在调用时执行不同的行为,您正在创建一个新操作(然后您什么都不做)来完成您的 TCS。
一般地能够构造一个基于任意事件的 Task
是相当困难的,并且在完全类型安全的情况下完成它是不可能的。 You can see some of the difficulties with doing that here。现在要根据特定对象上的特定事件创建 Task
,当然,这很容易(再次参见之前链接的问题)。
这主要源于 C# 语言本身在事件周围公开的功能,根本不允许这样做。