如果异步性不是必需的,并且您可以拥有一个几乎总是等待的线程,您可以通过为 lambda 提供一些阻塞方式来访问密钥来做到这一点。例如:
public void RegisterEvaluator(Func<Func<Key>, bool> evaluate);
…
keyUpper.RegisterEvaluator(
getKey => getKey() == Key.A && getKey() == Key.W);
RegisterEvaluator
然后将启动一个在循环中调用 lambda 的新线程,向其传递一个访问键的方法,如果此时没有可用的键,则阻塞,例如使用BlockingCollection<Key>
.
如果您认为这样做很浪费(确实如此),并且您可以使用 async-await,只需制作 lambdaasync
并将传入的方法也更改为异步方法:
public Task RegisterEvaluator(Func<Func<Task<Key>>, Task<bool>> evaluate);
…
keyUpper.RegisterEvaluator(
async getKey => await getKey() == Key.A && await getKey() == Key.W);
后一个版本(使用BlockBuffer<Key>
)的实现可能如下所示:
class KeyUpper
{
private readonly BufferBlock<Key> m_keyBuffer = new BufferBlock<Key>();
public async Task RegisterEvaluator(
Func<Func<Task<Key>>, Task<bool>> evaluate)
{
while (true)
{
if (await evaluate(m_keyBuffer.ReceiveAsync))
SomeResponse();
}
}
public void KeyUp(object sender, KeyEventArgs e)
{
m_keyBuffer.Post(e.Key);
}
private void SomeResponse()
{
// whatever
}
}
现在,我不确定您到底想如何处理匹配键,但我认为不是这样。例如,此示例代码将匹配键的序列BAW
,但不匹配AAW
。
另一种选择是不使用Func<Task<Key>>
,但是您可以多次等待的自定义可等待对象,并且每次执行此操作时都会给出一个键:
public Task RegisterEvaluator(Func<KeyAwaitable, Task<bool>> evaluate);
…
keyUpper.RegisterEvaluator(
async getKey => await getKey == Key.A && await getKey == Key.W);
但我认为这样做更令人困惑,更难做到。