C# Reactive Extensions:如何为Catch方法提供泛型空默认IObservable处理?
当然可以实现泛型的Catch处理!
你遇到的问题其实是匿名类型没法显式指定泛型参数,但借助C#的类型推断和Rx自身的API,完全能写出通用的Catch逻辑,返回对应类型的空IObservable。
方案1:直接利用Observable的ElementType属性
Rx的IObservable<T>可以通过ElementType属性获取元素的类型,哪怕是匿名类型也没问题。你可以直接把这个类型传给Observable.Empty,让它自动推断出泛型版本:
[TestMethod] public void ReactiveCatch() { var source = new[] { new { i = 1 }, new { i = 0 } }.ToObservable(); var a = source .Do(x => { var j = 1 / x.i; }) .Catch((Exception exc) => Observable.Empty(source.ElementType)) .ToEnumerable() .ToArray(); Assert.AreEqual(new { i = 1 }, a[0]); }
这里source.ElementType会返回匿名类型的Type对象,Observable.Empty会基于这个类型创建对应的IObservable<匿名类型>,完美适配你的场景。
方案2:写一个通用的扩展方法(更简洁)
如果需要多次使用这个逻辑,不如封装成一个泛型扩展方法,让代码更干净:
public static class ObservableExtensions { public static IObservable<T> CatchAndReturnEmpty<T>(this IObservable<T> source) { // 捕获所有异常,返回空序列 return source.Catch((Exception _) => Observable.Empty<T>()); } }
然后在你的测试代码里直接链式调用就行,C#编译器会自动从source的类型推断出T(包括匿名类型):
[TestMethod] public void ReactiveCatch() { var source = new[] { new { i = 1 }, new { i = 0 } }.ToObservable(); var a = source .Do(x => { var j = 1 / x.i; }) .CatchAndReturnEmpty() .ToEnumerable() .ToArray(); Assert.AreEqual(new { i = 1 }, a[0]); }
为什么这两种方法可行?
匿名类型虽然不能被显式命名,但C#的类型推断机制能在编译时识别它的类型。不管是通过source.ElementType还是扩展方法的泛型参数推断,都能让Rx正确生成对应类型的空Observable,不用你手动指定匿名类型(毕竟也没法手动指定)。
内容的提问来源于stack exchange,提问作者Hedgehog
相关产品推荐
相关产品推荐

