Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/neo4j/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Events Console.ReadLine()传递给C#事件_Events_Console_System.reactive_Readline - Fatal编程技术网

Events Console.ReadLine()传递给C#事件

Events Console.ReadLine()传递给C#事件,events,console,system.reactive,readline,Events,Console,System.reactive,Readline,我正在学习RX,希望使用Console.ReadLine作为可观察序列的源 我知道我可以使用“收益率回报”创建“IEnumerable”,但对于我的具体用例,我决定创建一个C#事件,这样可能会有许多观察者能够共享相同的键盘输入 这是我的密码: class Program { private delegate void OnNewInputLineHandler(string line); private static event OnNewInputLineHandler On

我正在学习RX,希望使用Console.ReadLine作为可观察序列的源

我知道我可以使用“收益率回报”创建“IEnumerable”,但对于我的具体用例,我决定创建一个C#事件,这样可能会有许多观察者能够共享相同的键盘输入

这是我的密码:

class Program
{
    private delegate void OnNewInputLineHandler(string line);

    private static event OnNewInputLineHandler OnNewInputLineEvent = _ => {};

    static void Main(string[] args)
    {
        Task.Run((Action) GetInput);

        var input = ConsoleInput();
        input.Subscribe(s=>Console.WriteLine("1: " + s));

        Thread.Sleep(30000);
    }

    private static void GetInput()
    {
        while (true)
            OnNewInputLineEvent(Console.ReadLine());
    }

    private static IObservable<string> ConsoleInput()
    {
        return Observable.Create<string>(
        (IObserver<string> observer) =>
        {
            OnNewInputLineHandler h = observer.OnNext;
            OnNewInputLineEvent += h;
            return Disposable.Create(() => { OnNewInputLineEvent -= h; });
        });
    }
}

有人能解释一下为什么会发生这种情况吗?

你正试图让自己的生活变得困难。几乎总有一种方法可以让Rx变得简单。这只是学习从功能上而不是程序上思考的问题

这就是您所需要的:

class Program
{
    static void Main(string[] args)
    {
        var subscription = ConsoleInput().Subscribe(s => Console.WriteLine("1: " + s));
        Thread.Sleep(30000);
        subscription.Dispose();
    }

    private static IObservable<string> ConsoleInput()
    {
        return
            Observable
                .FromAsync(() => Console.In.ReadLineAsync())
                .Repeat()
                .Publish()
                .RefCount()
                .SubscribeOn(Scheduler.Default);
    }
}
类程序
{
静态void Main(字符串[]参数)
{
var subscription=ConsoleInput();
睡眠(30000);
subscription.Dispose();
}
专用静态IObservable控制台输入()
{
返回
可观察
.FromAsync(()=>Console.In.ReadLineAsync())
.重复
.Publish()
.RefCount()
.SubscribeOn(Scheduler.Default);
}
}

这允许多个订阅者通过
.Publish().RefCount()
共享一个输入。并且
.SubscribeOn(Scheduler.Default)
将订阅推出到一个新线程,如果没有它,您将阻止订阅。

如果您移动
Task.Run((Action)GetInput)订阅后,您的代码将按需要工作。这是因为在原始版本中,
OnNewInputEvent(Console.ReadLine())
的第一次调用是在您将OnNewInputLineEvent连接到
observer.OnNext
之前运行的,谢谢您的提示!但它并没有回答我的问题——为什么有一个版本可以工作:var s=Console.ReadLine();ONNEWINPUTLINEVENT(s);而另一个释放第一个通知:OnNewInputLineEvent(Console.ReadLine())@纳坦-我要猜一个比赛条件,但很难证明。生成的IL非常相似——只需先将字符串存储在变量中。可能只是需要更长的时间执行一些命令。对我来说似乎有点狡猾。这也是我的第一个想法。我也浏览了IL代码,不明白为什么会有不同。但如果这是一个比赛条件,它将不会如此一致!在调试和发布版本以及直接运行或在调试器中运行时,都是相同的行为。我想我需要构建RX并尝试调试,但我不确定这是否值得。回答不错。我认为
中的第一行有一个额外的括号,缺少一个分号。正确!这两个版本之间的区别在于,在
var s=…
version中,GetInput挂起等待输入,并且在引用事件字段之前进行订阅。在短版本的
事件(Console.ReadLine())
中,编译器首先复制事件字段的值(此时该值只有一个非Rx订户),然后调用
ReadLine()
。即使订阅发生在输入第一个输入行之前,编译器使用的值也是前一个值。
class Program
{
    static void Main(string[] args)
    {
        var subscription = ConsoleInput().Subscribe(s => Console.WriteLine("1: " + s));
        Thread.Sleep(30000);
        subscription.Dispose();
    }

    private static IObservable<string> ConsoleInput()
    {
        return
            Observable
                .FromAsync(() => Console.In.ReadLineAsync())
                .Repeat()
                .Publish()
                .RefCount()
                .SubscribeOn(Scheduler.Default);
    }
}