我正在编写一个类,它封装了一个状态机,代表我的应用程序尝试与我自己的Web服务进行通信。基本状态是断开连接,连接,连接和需要凭据。我想过使用Rx通过BehaviorSubject发布状态更改的良好学习经验(希望这本身就是好的用法?)。我对此主题的一个状态是“需要凭证”,我需要在继续之前提示用户提供用户名和密码。出于本练习的目的,我们假设该类托管在Windows控制台应用程序中,并且我想提示用户
Console.WriteLine("Enter username");
var userName = Console.ReadLine();
Console.WriteLine("Enter password");
var password = Console.ReadLine();
由于我的Rx BehaviorSubject达到状态'RequiresCredentials',每次遇到此状态时都应该点击此状态。
我已将BehaviorSubject公开为自身(即未将其隐藏在Observable接口或其他任何内容之后)
public BehaviorSubject<ConnectionState> State { get; }
并希望这个凭据请求被阻止。
我应该使用什么过程正确订阅此主题,等待此输入并最终将控制权返回给调用线程?
答案 0 :(得分:2)
如果您不使用任务或等待,或任何异步,Rx订阅代码将在同一个线程上观察,并在您使用阻止代码时阻止。如果您不关心输入,那么您可以直接Subscribe
。如果您想使用输入的用户名/密码,则可以使用Select
。所以这会奏效:
class Program
{
static void Main(string[] args)
{
var subject = new BehaviorSubject<ConnectionState>(ConnectionState.Disconnected);
var getCredentials = subject.Where(cs => cs == ConnectionState.RequiresCredentials)
.Select(cs =>
{
Console.WriteLine("Enter username");
var userName = Console.ReadLine();
Console.WriteLine("Enter password");
var password = Console.ReadLine();
return Tuple.Create(userName, password);
});
using (var subscription = getCredentials.Subscribe())
{
Console.WriteLine("Changing to Connecting...");
subject.OnNext(ConnectionState.Connecting);
Console.WriteLine("Changing to RequiresCredentials...");
subject.OnNext(ConnectionState.RequiresCredentials);
Console.WriteLine("Connected.");
subject.OnNext(ConnectionState.Connected);
}
}
}
enum ConnectionState
{
Disconnected,
Connected,
Connecting,
RequiresCredentials
}
它产生以下输出:
Changing to Connecting...
Changing to RequiresCredentials...
Enter username
ThisIsMyUserName
Enter password
ThisIsMyPassword
Connected.
这是对Rx的一种相当向后的使用:如果您希望以迭代,程序的方式使用Rx,为什么不使用C#来节省自己的复杂性?