C# 在反应式编程中使用主题的替代方案?
在反应式编程中,通常不赞成使用C# 在反应式编程中使用主题的替代方案?,c#,system.reactive,C#,System.reactive,在反应式编程中,通常不赞成使用主题类型。在以下情况下,我使用主题来允许在创建通知的基础源之前订阅通知。是否有其他方法不使用主题 using System; using System.Reactive; using System.Reactive.Linq; using System.Reactive.Subjects; using System.Threading.Tasks; using Windows.Networking.Sockets; using Windows.Storage.Str
主题
类型。在以下情况下,我使用主题来允许在创建通知的基础源之前订阅通知。是否有其他方法不使用主题
using System;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
class Program
{
public static void Main()
{
var socket = new ObservableMessageWebSocket();
socket.Messages.Subscribe(Print); // Caller is allowed to subscribe before connect
var uri = new Uri("ws://mydomain.com/messages");
socket.ConnectAsync(uri).Wait(); // Caller is allowed to connect after subscribe
Console.ReadLine();
}
public static void Print(string message)
{
Console.WriteLine(message);
}
}
class ObservableMessageWebSocket
{
// Is there a way to get rid of this Subject?
private readonly Subject<string> subject = new Subject<string>();
private MessageWebSocket webSocket;
public IObservable<string> Messages => subject;
public async Task ConnectAsync(Uri uri)
{
webSocket = new MessageWebSocket();
webSocket.Control.MessageType = SocketMessageType.Utf8;
Observable
.FromEventPattern<MessageWebSocketMessageReceivedEventArgs>(webSocket, nameof(webSocket.MessageReceived))
.Select(ReadString)
.Subscribe(subject);
await webSocket.ConnectAsync(uri);
}
private static string ReadString(EventPattern<MessageWebSocketMessageReceivedEventArgs> pattern)
{
using (var reader = pattern.EventArgs.GetDataReader())
{
reader.UnicodeEncoding = UnicodeEncoding.Utf8;
return reader.ReadString(reader.UnconsumedBufferLength);
}
}
}
下面的代码也不起作用。同样的症状
class ObservableMessageWebSocket
{
private MessageWebSocket WebSocket { get; }
public IObservable<string> Messages { get; }
public ObservableMessageWebSocket()
{
WebSocket = new MessageWebSocket();
WebSocket.Control.MessageType = SocketMessageType.Utf8;
Messages = Observable.Create<string>(o => Observable
.FromEventPattern<MessageWebSocketMessageReceivedEventArgs>(WebSocket, nameof(WebSocket.MessageReceived))
.Select(ReadString)
.Subscribe(o));
}
private static string ReadString(EventPattern<MessageWebSocketMessageReceivedEventArgs> pattern)
{
using (var reader = pattern.EventArgs.GetDataReader())
{
reader.UnicodeEncoding = UnicodeEncoding.Utf8;
return reader.ReadString(reader.UnconsumedBufferLength);
}
}
public async Task ConnectAsync(Uri uri)
{
await WebSocket.ConnectAsync(uri);
}
}
类ObservaleMessageWebSocket
{
私有消息WebSocket WebSocket{get;}
公共IObservable消息{get;}
公共可观察消息WebSocket()
{
WebSocket=新消息WebSocket();
WebSocket.Control.MessageType=SocketMessageType.Utf8;
Messages=Observable.Create(o=>Observable
.FromEventPattern(WebSocket,名称(WebSocket.MessageReceived))
.选择(读取字符串)
.认购(o));
}
私有静态字符串ReadString(EventPattern模式)
{
使用(var reader=pattern.EventArgs.GetDataReader())
{
reader.unicodeincode=unicodeincode.Utf8;
返回reader.ReadString(reader.unsumedbufferlength);
}
}
公共异步任务ConnectAsync(Uri)
{
等待WebSocket.ConnectAsync(uri);
}
}
不知何故,下面的代码是有效的
class ObservableMessageWebSocket
{
private MessageWebSocket WebSocket { get; }
private event EventHandler<string> StringReceived;
public IObservable<string> Messages { get; }
public ObservableMessageWebSocket()
{
WebSocket = new MessageWebSocket();
WebSocket.Control.MessageType = SocketMessageType.Utf8;
WebSocket.MessageReceived += HandleEvent;
Messages = Observable
.FromEventPattern<string>(this, nameof(StringReceived))
.Select(p => p.EventArgs);
}
private void HandleEvent(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
{
var handler = StringReceived;
if (handler == null) return;
string message;
using (var reader = args.GetDataReader())
{
reader.UnicodeEncoding = UnicodeEncoding.Utf8;
message= reader.ReadString(reader.UnconsumedBufferLength);
}
handler.Invoke(this, message);
}
public async Task ConnectAsync(Uri uri)
{
await WebSocket.ConnectAsync(uri);
}
}
类ObservaleMessageWebSocket
{
私有消息WebSocket WebSocket{get;}
接收到私有事件EventHandler字符串;
公共IObservable消息{get;}
公共可观察消息WebSocket()
{
WebSocket=新消息WebSocket();
WebSocket.Control.MessageType=SocketMessageType.Utf8;
WebSocket.MessageReceived+=HandleEvent;
信息=可观察
.FromEventPattern(此,名称为(StringReceived))
.Select(p=>p.EventArgs);
}
私有void HandleEvent(MessageWebSocket发送者、MessageWebSocket MessageReceiveDeventargs参数)
{
var handler=StringReceived;
if(handler==null)返回;
字符串消息;
使用(var reader=args.GetDataReader())
{
reader.unicodeincode=unicodeincode.Utf8;
message=reader.ReadString(reader.unsumedbufferlength);
}
调用(这个,消息);
}
公共异步任务ConnectAsync(Uri)
{
等待WebSocket.ConnectAsync(uri);
}
}
对我来说,这三个似乎都很相似。为什么只有最后一个有效呢?主题并不普遍都是坏的,我也不认为你使用它的方式有什么严重的问题。我将参考和对它们及其使用进行一些合理的讨论
鉴于此,我建议如下(同时删除所有字段和公开属性):
公共异步任务ConnectAsync(Uri)
{
webSocket=新消息webSocket();
webSocket.Control.MessageType=SocketMessageType.Utf8;
var toReturn=可观测
.FromEventPattern(webSocket,名称(webSocket.MessageReceived))
.选择(读取字符串);
等待webSocket.ConnectAsync(uri);
回归回归;
}
这样,如果有人调用ConnectAsync
两次,他们可以得到单独的观察值 科目并不是普遍都不好,而且我认为你使用它的方式没有什么大问题。我将参考和对它们及其使用进行一些合理的讨论
鉴于此,我建议如下(同时删除所有字段和公开属性):
公共异步任务ConnectAsync(Uri)
{
webSocket=新消息webSocket();
webSocket.Control.MessageType=SocketMessageType.Utf8;
var toReturn=可观测
.FromEventPattern(webSocket,名称(webSocket.MessageReceived))
.选择(读取字符串);
等待webSocket.ConnectAsync(uri);
回归回归;
}
这样,如果有人调用
ConnectAsync
两次,他们可以得到单独的观察值 避开主题通常是个好主意。在代码中,您将主题直接暴露给调用代码。任何执行((主题)socket.Messages).OnCompleted()的使用者代码>将停止代码工作
您还将新建一个WebSocket
,以后应该将其处理掉
有一种方法可以避开这个主题,让它表现得更好
试试这个:
public IObservable<string> Connect(Uri uri)
{
return
Observable
.Using(
() =>
{
var webSocket = new MessageWebSocket();
webSocket.Control.MessageType = SocketMessageType.Utf8;
return webSocket;
},
webSocket =>
Observable
.FromAsync(() => webSocket.ConnectAsync(uri))
.SelectMany(u =>
Observable
.FromEventPattern<MessageWebSocketMessageReceivedEventArgs>(webSocket, nameof(webSocket.MessageReceived))
.SelectMany(pattern =>
Observable
.Using(
() =>
{
var reader = pattern.EventArgs.GetDataReader();
reader.UnicodeEncoding = UnicodeEncoding.UTF8;
return reader;
},
reader => Observable.Return(reader.ReadString(reader.UnconsumedBufferLength))))));
}
公共IObservable连接(Uri)
{
返回
可观察
.使用(
() =>
{
var webSocket=新消息webSocket();
webSocket.Control.MessageType=SocketMessageType.Utf8;
返回网袋;
},
webSocket=>
可观察
.FromAsync(()=>webSocket.ConnectAsync(uri))
.选择多个(u=>
可观察
.FromEventPattern(webSocket,名称(webSocket.MessageReceived))
.SelectMany(模式=>
可观察
.使用(
() =>
{
var reader=pattern.EventArgs.GetDataReader();
reader.unicodeincode=unicodeincode.UTF8;
返回读取器;
},
reader=>Observable.Return(reader.ReadString(reader.unsumedbufferlength()()()));
}
以下是如何使用现有代码样式避免主题:
public IObservable<string> ConnectAsync(Uri uri)
{
return
Observable
.Create<string>(async o =>
{
var webSocket = new MessageWebSocket();
webSocket.Control.MessageType = SocketMessageType.Utf8;
var subscription = Observable
.FromEventPattern<MessageWebSocketMessageReceivedEventArgs>(webSocket, nameof(webSocket.MessageReceived))
.Select(ReadString)
.Subscribe(o);
await webSocket.ConnectAsync(uri);
return subscription;
});
}
public IObservable ConnectAsync(Uri)
{
返回
可观察
.Create(异步o=>
{
var webSocket=新消息webSocket();
public IObservable<string> Connect(Uri uri)
{
return
Observable
.Using(
() =>
{
var webSocket = new MessageWebSocket();
webSocket.Control.MessageType = SocketMessageType.Utf8;
return webSocket;
},
webSocket =>
Observable
.FromAsync(() => webSocket.ConnectAsync(uri))
.SelectMany(u =>
Observable
.FromEventPattern<MessageWebSocketMessageReceivedEventArgs>(webSocket, nameof(webSocket.MessageReceived))
.SelectMany(pattern =>
Observable
.Using(
() =>
{
var reader = pattern.EventArgs.GetDataReader();
reader.UnicodeEncoding = UnicodeEncoding.UTF8;
return reader;
},
reader => Observable.Return(reader.ReadString(reader.UnconsumedBufferLength))))));
}
public IObservable<string> ConnectAsync(Uri uri)
{
return
Observable
.Create<string>(async o =>
{
var webSocket = new MessageWebSocket();
webSocket.Control.MessageType = SocketMessageType.Utf8;
var subscription = Observable
.FromEventPattern<MessageWebSocketMessageReceivedEventArgs>(webSocket, nameof(webSocket.MessageReceived))
.Select(ReadString)
.Subscribe(o);
await webSocket.ConnectAsync(uri);
return subscription;
});
}
void Main()
{
Connect(new Uri("https://stackoverflow.com/")).Subscribe(x => Console.WriteLine(x.Substring(0, 24)));
}
public IObservable<string> Connect(Uri uri)
{
return
Observable
.Create<string>(async o =>
{
var webClient = new WebClient();
webClient.UseDefaultCredentials = true;
var subscription =
Observable
.Using(
() => new CompositeDisposable(webClient, Disposable.Create(() => Console.WriteLine("Disposed!"))),
_ =>
Observable
.FromEventPattern<DownloadStringCompletedEventHandler, DownloadStringCompletedEventArgs>(
h => webClient.DownloadStringCompleted += h, h => webClient.DownloadStringCompleted -= h)
.Take(1))
.Select(x => x.EventArgs.Result)
.Subscribe(o);
await webClient.DownloadStringTaskAsync(uri);
return subscription;
});
}