你如何使用 Rx 请求用户输入?
How do you request user input using Rx?
我正在编写一个 class,它封装了一个状态机,表示我的应用程序尝试与我自己的 Web 服务进行通信。基本状态是断开、连接、连接和需要凭据。我想获得有关使用 Rx 通过 BehaviorSubject 发布状态更改的良好学习经验(希望这本身就是很好的用法?)。我对此主题的状态之一是 'Requiring Credentials',我需要提示用户在继续之前提供用户名和密码。出于本练习的目的,让我们假设 class 托管在 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; }
并希望阻止此凭据请求。
我应该使用什么进程来正确订阅这个主题,等待这个输入并最终将控制权返回给调用线程?
如果您不使用任务或等待,或任何异步,Rx 订阅代码将在同一线程上观察,如果您使用阻塞代码则阻塞。如果你不关心输入,那么你可以直接Subscribe
。如果你想使用输入的username/password,那么你可以使用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# 来节省复杂性呢?
我正在编写一个 class,它封装了一个状态机,表示我的应用程序尝试与我自己的 Web 服务进行通信。基本状态是断开、连接、连接和需要凭据。我想获得有关使用 Rx 通过 BehaviorSubject 发布状态更改的良好学习经验(希望这本身就是很好的用法?)。我对此主题的状态之一是 'Requiring Credentials',我需要提示用户在继续之前提供用户名和密码。出于本练习的目的,让我们假设 class 托管在 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; }
并希望阻止此凭据请求。
我应该使用什么进程来正确订阅这个主题,等待这个输入并最终将控制权返回给调用线程?
如果您不使用任务或等待,或任何异步,Rx 订阅代码将在同一线程上观察,如果您使用阻塞代码则阻塞。如果你不关心输入,那么你可以直接Subscribe
。如果你想使用输入的username/password,那么你可以使用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# 来节省复杂性呢?