按下IObservable键

时间:2012-05-20 17:08:30

标签: c# .net system.reactive

所以我可以尝试使用Reactive Extensions,我想创建一个由用户按下的IObservable键。我怎么能这样做?

这适用于C#控制台应用程序

4 个答案:

答案 0 :(得分:4)

尝试此操作以获得可观察的读取键序列:

        IObservable<System.ConsoleKeyInfo> keys =
            Observable
                .Defer(() =>
                    Observable
                        .Start(() =>
                            Console.ReadKey()))
                .Repeat();

我测试了它,它就像一种享受。

答案 1 :(得分:3)

ReadKey()的阻止版本存在问题,因为如果您处理订阅,它仍然会提示您按一个键。

如果你想要一个干净的取消订阅,即能够取消提示,那么(不幸的是)必须采用轮询方式。

Observable.Interval(TimeSpan.FromMilliseconds(100))
          .Where(_ => Console.KeyAvailable)
          .Select(_ => (char)Console.ReadKey(false).Key)

现在,您可以使用AmbObservable.Timer这个流做一些很酷的事情来设置按键超时。

答案 2 :(得分:0)

我没有看到任何方式如何异步读取按键,所以我认为你必须在一个单独的线程上使用同步Console.ReadKey()以及Subject<T>。类似的东西:

IObservable<ConsoleKeyInfo> ObserveKeysUntilEscape()
{
    var keys = new Subject<ConsoleKeyInfo>();

    Task.Run(
        () =>
        {
            ConsoleKeyInfo key;
            do
            {
                key = Console.ReadKey();
                keys.OnNext(key);
            } while (key.Key != ConsoleKey.Escape);
            keys.OnCompleted();
        });

    return keys;
}

答案 3 :(得分:0)

@svick方法的替代方法是将ReadKey循环设为Enumerable,然后转换为Observable。这将它放在后台。

    static IEnumerable<ConsoleKeyInfo> KeyPresses()
    {
        ConsoleKeyInfo key;
        do
        {
            key = Console.ReadKey();
            yield return key;
        } while (key.Key != ConsoleKey.Escape);
    }

我们可以在线程池上生成observable:

        var keys = KeyPresses().ToObservable(System.Reactive.Concurrency.Scheduler.ThreadPool);
        keys.Subscribe(key => Console.WriteLine("Pressed: {0}", key.Key));  

等待Escape密钥的主线程:

        keys.Where(key => key.Key == ConsoleKey.Escape).First();