![](/img/trans.png)
[英]How to get IObservable<T>.ToTask functionality in silverlight
[英]Prevent InvalidOperationException when using ToTask on IObservable
我需要以某種方式防止在不產生任何值的Observable上調用ToTask時引發的InvalidOperationException
。
我所看到的是,ToTask方法創建的實例ToTaskObserver
並希望至少有一個值不拋出異常:
private sealed class ToTaskObserver<TResult> : SafeObserver<TResult>
{
//[...]
private bool _hasValue;
private TResult _lastValue;
public ToTaskObserver(TaskCompletionSource<TResult> tcs, CancellationToken ct)
{
//[...]
}
public override void OnNext(TResult value)
{
_hasValue = true;
_lastValue = value;
}
//[...]
public override void OnCompleted()
{
if (_hasValue)
{
_tcs.TrySetResult(_lastValue);
}
else
{
_tcs.TrySetException(new InvalidOperationException(Strings_Linq.NO_ELEMENTS));
}
//[...]
}
//[...]
}
我發現的唯一解決方案是模仿擴展方法,並通過合並將虛擬記錄插入Observable中:
public static Task<Record<TKey, TValue>> ToTask<TKey, TValue>(
this IObservable<Record<TKey, TValue>> source, CancellationToken token)
{
var pseudoObservable = new[] {Record.Create<TKey, TValue>(default, default)}.ToObservable();
return source.Merge(pseudoObservable).ToTask(token);
}
這個問題尤其與ToTask
方法有關。 我知道,當我使用Subscribe
方法時,我不會遇到這個問題。
有人對此有更好的解決方案嗎? 我有可觀察的場景將沒有任何記錄的情況。
這里有很多選擇:
.ToList()
。 default(T)
不是有效值,則可以使用.LastOrDefaultAsync()
,然后檢查默認值。 default(T)
是有效值,則仍可以使用.ToList()
,或者可以使用Option
樣式類: Option
類看起來像這樣,除非我忘記了C#的內置選項(F#有一個)。
public class Optional<T>
{
private readonly bool _hasValue;
private readonly T _value;
public Optional(T t)
{
_value = t;
_hasValue = true;
}
public Optional()
{
_hasValue = false;
_value = default(T);
}
public bool HasValue => _hasValue;
public T Value
{
get
{
if(HasValue)
return _value;
else
throw new InvalidOperationException("No value present");
}
}
}
public static class X {
public static IObservable<Optional<T>> ToOptional<T>(this IObservable<T> source)
{
return source.Publish(_source => _source
.Select(t => new Optional<T>(t))
.LastOrDefaultAsync()
.Select(n => n.Equals(default(Optional<T>)) ? new Optional<T>() : n)
);
}
}
我更喜歡Optional
選項而不是List
,因為當您知道最大值為一個時, List
看起來很有趣。 但是取決於你。 這是示例用法:
var fortyTwoList = await Observable.Return(42).ToList();
var noneList = await Observable.Empty<int>().ToList();
var fortyTwo = await Observable.Return(42).ToOptional();
var none = await Observable.Empty<int>().ToOptional();
none.Dump(); //Linqpad
fortyTwo.Dump(); //Linqpad
noneList.Dump(); //Linqpad
fortyTwoList.Dump(); //Linqpad
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.