等待的lambdas

时间:2012-01-22 17:15:42

标签: c# .net delegates lambda async-await

密钥监听器中的动态评估

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的密钥事件序列之后调用SomeResponse():A 2:W 3 :A
  • 显然目前永远不会发生,因为该方法一直运行到最后,key == Key.W永远不会成为现实
  • 它可能是不可能的,但有没有办法使方法调用自动返回下一行,如果它的计算结果为false但返回到它直到该行计算结果为true,之后直到该行,并在那之后直到方法结束?
  • 即。可能有一种简单的方法来提供这种类似的lambda表达式吗?

1 个答案:

答案 0 :(得分: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,只需创建lambda async并将传入的方法更改为异步方法:

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);

但我认为以这种方式这样做会更加困惑和困难。