如果我有一个INPC支持类数字,其中包含两个属性 A 和 B 。我可以编写像
这样的代码Numbers numbers = new Numbers();
IObservable<double> o = numbers.WhenAnyValue(p=>p.A,p=>p.B,(a,b)=>a/b);
WhenAnyValue是ReactiveUI库中的一个实用程序方法,用于从属性更改事件中组合observable。如果我然后写。
o.Subscribe(v=>Console.WriteLine(v));
只要A或B发生变化,它就会打印 a / b 。这一切都很好,直到我设置
numbers.B = 0;
现在 a / b 会抛出DivideByZeroException,observable将终止。然而,这是一个用户界面。我不希望observable终止。我只是想要忽略该异常或记录它并继续前进。第一次尝试是看到IObservable包含一个名为Retry的扩展方法,它将在异常后重新连接到observable。我们试试
Numbers numbers = new Numbers();
IObservable<double> o = numbers
.WhenAnyValue(p=>p.A,p=>p.B,(a,b)=>a/b)
.Retry();
o.Subscribe(v=>Console.WriteLine(v));
但是当我执行 numbers.B = 0 时,重试将忽略该异常并重新连接,并会立即一次又一次地失败,因为 WhenAnyValue 总是会发送一个事件订阅。
所以看起来我需要的是一个重试,它会在重新连接后忽略第一个输入 iff 它与导致错误断开第一个输入的输入相同,除了我不认为这可以用RX。
有什么想法吗?
以下测试用例不会终止。
public class Numbers : ReactiveObject
{
int _A;
public int A
{
get { return _A; }
set { this.RaiseAndSetIfChanged(ref _A, value); }
}
int _B;
public int B
{
get { return _B; }
set { this.RaiseAndSetIfChanged(ref _B, value); }
}
}
[Fact]
public void TestShouldTerminate()
{
var numbers = new Numbers();
var o = numbers
.WhenAnyValue(p => p.A, p => p.B, Tuple.Create)
.Select(v=>v.Item1/v.Item2)
.Select(v=>v+1)
.Retry();
double value = 0;
o.Subscribe(v => value = v);
numbers.A = 10;
numbers.B = 20;
value.Should().Be(1.5);
}
}
}
}
答案 0 :(得分:0)
这不能在vanilla RX中处理。我创建了一个名为
的包装器IObservableExceptional
IObserverExceptional
更改了RX中错误处理的标准合同。错误现在不再终止observable。它支持LINQ,对于大多数用途应该是相当透明的。通过的测试用例是
[Fact]
public void ErrorsCanBePropogated()
{
var numbers = new Numbers();
var list = new List<double>();
var errors = new List<Exception>();
numbers
.WhenAnyValue(p => p.A, p => p.B, Tuple.Create)
.ToObservableExceptional()
.Select(v => v.Item1/v.Item2)
.Subscribe(onNext: val=>list.Add(val), onError:err=>errors.Add(err));
list.Count.Should().Be(0);
errors.Count.Should().Be(1);
numbers.A = 10;
list.Count.Should().Be(0);
errors.Count.Should().Be(2);
numbers.B = 5;
list.Count.Should().Be(1);
list[0].Should().Be(2.0);
errors.Count.Should().Be(2);
}
三个新界面
public interface IObservableExceptional<T>
{
void Subscribe(IObserverExceptional<T> observer);
IObservable<IExceptional<T>> Observable { get; }
}
public interface IObserverExceptional<T>
{
void OnNext(IExceptional<T> t);
void OnCompleted();
IObserver<IExceptional<T>> Observer { get; }
}
public interface IExceptional<out T> : IEnumerable<T>
{
bool HasException { get; }
Exception Exception { get; }
T Value { get; }
string ToMessage();
void ThrowIfHasException();
}
IObservableException和IExceptional都支持LINQ(即它们是Monads)
IObservableExceptional的Select或SelectMany组合器中抛出的任何异常都包装为IExceptional对象并传递给订阅者。错误不会终止订阅。
存储库位于