【发布时间】:2018-06-23 11:52:15
【问题描述】:
我正在尝试将现有的基于事件的 API 转换为 Reactive Observable API。我正在使用的具体 API 是 Xamarin.iOS 中的 NSNetServiceBrowser。此 API 让您可以使用 Zeroconf/Bonjour 浏览网络设备。但是,该问题适用于任何此类 API。
NsNetServiceBrowser 提供各种感兴趣的事件:
- FoundService
- NotSearched
- ServiceRemoved
发现服务时引发FoundService事件,搜索失败时引发NotSearched。
我想将 FoundService 和 NotSerched 事件组合成 NSNetService 的 observable。
我当前的实现如下所示:
public IObservable<NSNetService> Search()
{
var foundObservable = Observable
.FromEventPattern<NSNetServiceEventArgs>(
h => serviceBrowser.FoundService += h,
h => serviceBrowser.FoundService -= h)
.Select(x => x.EventArgs);
var notSearchedObservable = Observable
.FromEventPattern<NSNetServiceErrorEventArgs>(
h => serviceBrowser.NotSearched += h,
h => serviceBrowser.NotSearched -= h)
.Select(x => x.EventArgs);
var serviceObservable = Observable.Create(
(IObserver<NSNetServiceEventArgs> observer) =>
{
notSearchedObservable.Subscribe(n =>
{
string errorMessage = $"Search for {serviceType} failed:";
foreach (var kv in n.Errors)
{
log.Error($"\t{kv.Key}: {kv.Value}");
errorMessage += $" ({kv.Key}, {kv.Value})";
}
observer.OnError(new Exception(errorMessage));
});
foundObservable.Subscribe(observer);
return System.Reactive.Disposables.Disposable.Empty;
}).Select(x => x.Service);
serviceBrowser.SearchForServices(serviceType, domain);
return serviceObservable;
}
代码看起来很笨拙,我有一种直觉,我没有正确使用System.Reactive?有没有一种更优雅的方式来组合事件对,其中一个正在产生,另一个是发出错误信号?这是 .NET 中现有的基于事件的 API 中的常见模式。
这是一个小型控制台应用程序(仅取决于 System.Reactive),说明了我想要 Reactify 的 API 类型:
using System;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace ReactiveLearning
{
class Program
{
static void Main(string[] args)
{
var browser = new ServiceBrowser();
var observableFound =
Observable.FromEventPattern<ServiceFoundEventArgs>(
h => browser.ServiceFound += h,
h => browser.ServiceFound -= h)
.Select(e => e.EventArgs.Service);
var observableError =
Observable.FromEventPattern<ServiceSearchErrorEventArgs>(
h => browser.ServiceError += h,
h => browser.ServiceError -= h);
var foundSub = observableFound.Subscribe(s =>
{
Console.WriteLine($"Found service: {s.Name}");
}, () =>
{
Console.WriteLine("Found Completed");
});
var errorSub = observableError.Subscribe(e =>
{
Console.WriteLine("ERROR!");
}, () =>
{
Console.WriteLine("Error Completed");
});
browser.Search();
Console.ReadLine();
foundSub.Dispose();
errorSub.Dispose();
Console.WriteLine();
}
}
class ServiceBrowser
{
public EventHandler<ServiceFoundEventArgs> ServiceFound;
public EventHandler<ServiceSearchErrorEventArgs> ServiceError;
public void Search()
{
Task.Run(async () =>
{
for (var i = 0; i < 5; ++i)
{
await Task.Delay(1000);
ServiceFound?.Invoke(this, new ServiceFoundEventArgs(new Service($"Service {i}")));
}
var r = new Random();
if (r.NextDouble() > 0.5)
{
ServiceError?.Invoke(this, new ServiceSearchErrorEventArgs());
}
});
}
}
class ServiceFoundEventArgs : EventArgs
{
public Service Service { get; private set; }
public ServiceFoundEventArgs(Service service) => Service = service;
}
class ServiceSearchErrorEventArgs : EventArgs {}
class Service
{
public event EventHandler<EventArgs> AddressResolved;
public event EventHandler<EventArgs> ErrorResolvingAddress;
public string Name { get; private set; }
public string Address { get; private set; }
public Service(string name) => Name = name;
public void ResolveAddress()
{
Task.Run(async () =>
{
await Task.Delay(500);
var r = new Random();
if (r.NextDouble() > 0.5)
{
Address = $"http://{Name}.com";
AddressResolved?.Invoke(this, EventArgs.Empty);
}
else
{
ErrorResolvingAddress?.Invoke(this, EventArgs.Empty);
}
});
}
}
}
【问题讨论】:
-
是的,每当你这样做
return Disposable.Empty;时,你就做错了。 -
它会像
return foundObservable.Select(x => x.Service).Merge(notSearchedObservable.Select(x => x.Service));这样简单,但是你还没有发布你的类定义,所以我不能肯定地说。你能发一个minimal reproducible example吗? -
@Enigmativity 我不想合并它们 - 我想要一个 Observable,其中由 notSearchedObservable 生成的元素会引发错误(不生成元素)。我会看看我是否可以创建一个我想要“反应”的通用小例子
-
这是一个小型控制台应用程序(仅取决于 System.Reactive),说明了我想要 Reactify 的 API 类型:gist.github.com/follesoe/60669ea2c5112cd733181d7870ba93da
-
如果出现错误应该立即停止您的 observable 还是应该继续并能够报告多个错误?
标签: system.reactive