3
3
// See the LICENSE file in the project root for more information.
4
4
5
5
using System . Reactive . Concurrency ;
6
+ using System . Reactive . Disposables ;
6
7
using System . Reactive . Linq ;
7
8
using System . Reactive . Linq . ObservableImpl ;
8
9
using System . Reactive . Subjects ;
@@ -58,48 +59,30 @@ public static IObservable<Unit> ToObservable(this Task task, IScheduler schedule
58
59
59
60
private static IObservable < Unit > ToObservableImpl ( Task task , IScheduler scheduler )
60
61
{
61
- var res = default ( IObservable < Unit > ) ;
62
-
63
62
if ( task . IsCompleted )
64
63
{
65
64
scheduler = scheduler ?? ImmediateScheduler . Instance ;
66
65
67
66
switch ( task . Status )
68
67
{
69
- case TaskStatus . RanToCompletion :
70
- res = new Return < Unit > ( Unit . Default , scheduler ) ;
71
- break ;
72
68
case TaskStatus . Faulted :
73
- res = new Throw < Unit > ( task . Exception . InnerException , scheduler ) ;
74
- break ;
69
+ return new Throw < Unit > ( task . Exception . InnerException , scheduler ) ;
75
70
case TaskStatus . Canceled :
76
- res = new Throw < Unit > ( new TaskCanceledException ( task ) , scheduler ) ;
77
- break ;
71
+ return new Throw < Unit > ( new TaskCanceledException ( task ) , scheduler ) ;
78
72
}
79
- }
80
- else
81
- {
82
- //
83
- // Separate method to avoid closure in synchronous completion case.
84
- //
85
- res = ToObservableSlow ( task , scheduler ) ;
86
- }
87
73
88
- return res ;
89
- }
74
+ return new Return < Unit > ( Unit . Default , scheduler ) ;
75
+ }
90
76
91
- private static IObservable < Unit > ToObservableSlow ( Task task , IScheduler scheduler )
92
- {
93
77
var subject = new AsyncSubject < Unit > ( ) ;
94
-
95
78
var options = GetTaskContinuationOptions ( scheduler ) ;
96
79
97
- task . ContinueWith ( t => ToObservableDone ( task , subject ) , options ) ;
80
+ task . ContinueWith ( ( t , subjectObject ) => t . EmitTaskResult ( ( AsyncSubject < Unit > ) subjectObject ) , subject , options ) ;
98
81
99
- return ToObservableResult ( subject , scheduler ) ;
82
+ return subject . ToObservableResult ( scheduler ) ;
100
83
}
101
84
102
- private static void ToObservableDone ( Task task , IObserver < Unit > subject )
85
+ private static void EmitTaskResult ( this Task task , IObserver < Unit > subject )
103
86
{
104
87
switch ( task . Status )
105
88
{
@@ -116,6 +99,26 @@ private static void ToObservableDone(Task task, IObserver<Unit> subject)
116
99
}
117
100
}
118
101
102
+ internal static IDisposable Subscribe ( this Task task , IObserver < Unit > observer )
103
+ {
104
+ if ( task . IsCompleted )
105
+ {
106
+ task . EmitTaskResult ( observer ) ;
107
+ return Disposable . Empty ;
108
+ }
109
+
110
+ var cts = new CancellationDisposable ( ) ;
111
+
112
+ task . ContinueWith (
113
+ ( t , observerObject ) => t . EmitTaskResult ( ( IObserver < Unit > ) observerObject ) ,
114
+ observer ,
115
+ cts . Token ,
116
+ TaskContinuationOptions . ExecuteSynchronously ,
117
+ TaskScheduler . Default ) ;
118
+
119
+ return cts ;
120
+ }
121
+
119
122
/// <summary>
120
123
/// Returns an observable sequence that propagates the result of the task.
121
124
/// </summary>
@@ -160,48 +163,30 @@ public static IObservable<TResult> ToObservable<TResult>(this Task<TResult> task
160
163
161
164
private static IObservable < TResult > ToObservableImpl < TResult > ( Task < TResult > task , IScheduler scheduler )
162
165
{
163
- var res = default ( IObservable < TResult > ) ;
164
-
165
166
if ( task . IsCompleted )
166
167
{
167
168
scheduler = scheduler ?? ImmediateScheduler . Instance ;
168
169
169
170
switch ( task . Status )
170
171
{
171
- case TaskStatus . RanToCompletion :
172
- res = new Return < TResult > ( task . Result , scheduler ) ;
173
- break ;
174
172
case TaskStatus . Faulted :
175
- res = new Throw < TResult > ( task . Exception . InnerException , scheduler ) ;
176
- break ;
173
+ return new Throw < TResult > ( task . Exception . InnerException , scheduler ) ;
177
174
case TaskStatus . Canceled :
178
- res = new Throw < TResult > ( new TaskCanceledException ( task ) , scheduler ) ;
179
- break ;
175
+ return new Throw < TResult > ( new TaskCanceledException ( task ) , scheduler ) ;
180
176
}
181
- }
182
- else
183
- {
184
- //
185
- // Separate method to avoid closure in synchronous completion case.
186
- //
187
- res = ToObservableSlow ( task , scheduler ) ;
188
- }
189
177
190
- return res ;
191
- }
178
+ return new Return < TResult > ( task . Result , scheduler ) ;
179
+ }
192
180
193
- private static IObservable < TResult > ToObservableSlow < TResult > ( Task < TResult > task , IScheduler scheduler )
194
- {
195
181
var subject = new AsyncSubject < TResult > ( ) ;
196
-
197
182
var options = GetTaskContinuationOptions ( scheduler ) ;
198
183
199
- task . ContinueWith ( t => ToObservableDone ( task , subject ) , options ) ;
184
+ task . ContinueWith ( ( t , subjectObject ) => t . EmitTaskResult ( ( AsyncSubject < TResult > ) subjectObject ) , subject , options ) ;
200
185
201
- return ToObservableResult ( subject , scheduler ) ;
186
+ return subject . ToObservableResult ( scheduler ) ;
202
187
}
203
188
204
- private static void ToObservableDone < TResult > ( Task < TResult > task , IObserver < TResult > subject )
189
+ private static void EmitTaskResult < TResult > ( this Task < TResult > task , IObserver < TResult > subject )
205
190
{
206
191
switch ( task . Status )
207
192
{
@@ -240,7 +225,7 @@ private static TaskContinuationOptions GetTaskContinuationOptions(IScheduler sch
240
225
return options ;
241
226
}
242
227
243
- private static IObservable < TResult > ToObservableResult < TResult > ( AsyncSubject < TResult > subject , IScheduler scheduler )
228
+ private static IObservable < TResult > ToObservableResult < TResult > ( this AsyncSubject < TResult > subject , IScheduler scheduler )
244
229
{
245
230
if ( scheduler != null )
246
231
{
@@ -250,6 +235,26 @@ private static IObservable<TResult> ToObservableResult<TResult>(AsyncSubject<TRe
250
235
return subject . AsObservable ( ) ;
251
236
}
252
237
238
+ internal static IDisposable Subscribe < TResult > ( this Task < TResult > task , IObserver < TResult > observer )
239
+ {
240
+ if ( task . IsCompleted )
241
+ {
242
+ task . EmitTaskResult ( observer ) ;
243
+ return Disposable . Empty ;
244
+ }
245
+
246
+ var cts = new CancellationDisposable ( ) ;
247
+
248
+ task . ContinueWith (
249
+ ( t , observerObject ) => t . EmitTaskResult ( ( IObserver < TResult > ) observerObject ) ,
250
+ observer ,
251
+ cts . Token ,
252
+ TaskContinuationOptions . ExecuteSynchronously ,
253
+ TaskScheduler . Default ) ;
254
+
255
+ return cts ;
256
+ }
257
+
253
258
/// <summary>
254
259
/// Returns a task that will receive the last value or the exception produced by the observable sequence.
255
260
/// </summary>
0 commit comments