2

关键监听器中的动态评估

public class KeyUpper {
    Func<Key, bool> _evaluate;

    public void RegisterEvaluator(Func<Key, bool> evaluate){
        _evaluate = evaluate;
    }

    public void KeyUp(object sender, KeyEventArgs e){
        if (_evaluate(e.KeyCode))
            SomeResponse();
    }

    public void SomeResponse(){
        // ...
    }
}

这个 Lambda 应该在每一行上等待

keyUpper.RegisterEvaluator(key => 
    {
    if (key == Key.A)
        if (key == Key.W)
            if (key == Key.A)
                return true;
    }
);
  • 即客户端代码将提供对同一参数的一系列评估,key期望每一行评估都将被等待,以便在 1:A 2:W 3:A 的一系列 keyup 事件之后调用 SomeResponse()
  • 显然目前这永远不会发生,因为该方法一直运行到最后并且key == Key.W永远不会是真的
  • 这可能是不可能的,但是有没有办法让方法调用自动从下一行返回,如果它评估为假,但返回它直到该行评估为真,然后一直到之后的行,然后到在那之后直到方法结束?
  • 即是否有一种简单的方法来提供这种可等待的 lambda 表达式?
4

1 回答 1

2

如果异步性不是必需的,并且您可以拥有一个几乎总是等待的线程,您可以通过为 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);

但我认为这样做更令人困惑,更难做到。

于 2012-01-22T19:39:24.010 回答