所以我可以尝试使用Reactive Extensions,我想创建一个由用户按下的IObservable键。我怎么能这样做?
这适用于C#控制台应用程序
答案 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)
现在,您可以使用Amb
为Observable.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();