ожидаемые лямбды - PullRequest
       13

ожидаемые лямбды

2 голосов
/ 22 января 2012

Динамические оценки в ключевом слушателе

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(){
        // ...
    }
}

Эта лямбда-функция должна ожидать в каждой строке

keyUpper.RegisterEvaluator(key => 
    {
    if (key == Key.A)
        if (key == Key.W)
            if (key == Key.A)
                return true;
    }
);
  • , т. Е. Код клиента будет обеспечивать серию оценок для одной и той же key аргумент с ожиданием того, что каждая строка оценки будет ожидаемой, так что SomeResponse () будет вызван после последовательности событий keyup 1: A 2: W 3: A
  • , очевидно, в тот момент, когданикогда не произойдет, потому что метод выполняется до конца и key == Key.W никогда не будет истинным
  • это может быть невозможно, но есть способ заставить вызов метода автоматически возвращаться из следующей строки, если он оценивается какfalse, но возвращаться к нему до тех пор, пока эта строка не станет истинной, после этого до строки после этого и до строки после этого до конца метода?
  • то есть, может быть, существует простой способ предоставления ожидаемоголямбда-выражения такого рода?

1 Ответ

2 голосов
/ 22 января 2012

Если асинхронность не является обязательным требованием, и у вас все в порядке с одним потоком, который почти всегда ожидает, вы можете сделать это, предоставив лямбде некоторый блокирующий доступ к ключу.Например:

public void RegisterEvaluator(Func<Func<Key>, bool> evaluate);

…

keyUpper.RegisterEvaluator(
    getKey => getKey() == Key.A && getKey() == Key.W);

RegisterEvaluator будет тогда раскручивать новый поток, который вызывает лямбда в цикле, передавая ему метод, который обращается к ключу, блокируя, если в данный момент ключ недоступен, дляпример использования BlockingCollection<Key>.

Если вы думаете, что делать это таким образом бесполезно (так оно и есть), и вы можете использовать async-await, просто сделайте лямбду 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);

Но я думаю, что делать это таким образом сложнее и сложнее.

...