Just to supplement @Asti's answer a bit here, and perhaps help you with your frustration:
An observable isn't a physical 'thing', it's more a logical concept. Rx is often compared to LINQ, and it's a fair comparison much of the time. It breaks down though when you start talking data structures: LINQ's enumerables are similar enough to Lists for learning purposes.
However, on the Rx side, there's simply no good equivalent to List. An observable is a transient data structure, all operators deal with this transient state. If you're looking for a permanent state, you're leaving Rx.
Having said that, converting an observable to some sort of state is a common problem, and there are some packages that may help you: ReactiveUI is perhaps the most known. ReactiveProperty is another. Both of these packages are flawed, but may help you.
If you're simply looking for an easier way to get a backing field, without boiler-plating out a backing field, this will work:
public static class ReactivePropertyExtensions { public static ReactiveProperty<T> ToReactiveProperty<T>(this IObservable<T> source) { return new ReactiveProperty<T>(source); } public static ReactiveProperty<T> ToReactiveProperty<T>(this IObservable<T> source, T defaultValue) { return new ReactiveProperty<T>(source, defaultValue); } } public class ReactiveProperty<T> : IDisposable { private IObservable<T> Source { get; } private IDisposable Subscription { get; } public T Value { get; private set; } public ReactiveProperty(IObservable<T> source) : this(source, default(T)) { } public ReactiveProperty(IObservable<T> source, T defaultValue) { Value = defaultValue; Source = source; Subscription = source.Subscribe(t => Value = t); } public void Dispose() { Subscription.Dispose(); } }
Example use:
var ticker = Observable.Interval(TimeSpan.FromSeconds(1)) .Publish().RefCount(); var latestTickerValue = ticker.ToReactiveProperty(); Console.WriteLine(latestTickerValue.Value); await Task.Delay(TimeSpan.FromSeconds(1)); Console.WriteLine(latestTickerValue.Value); await Task.Delay(TimeSpan.FromSeconds(3)); Console.WriteLine(latestTickerValue.Value);