-
Notifications
You must be signed in to change notification settings - Fork 56
/
AdapterExtensions.cs
210 lines (197 loc) · 10.3 KB
/
AdapterExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using Dasync.Collections.Internals;
namespace Dasync.Collections
{
#if !NETSTANDARD2_1 && !NETSTANDARD2_0 && !NET461
/// <summary>
/// Converts generic IEnumerable to IAsyncEnumerable
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static class EnumerableExtensions
{
/// <summary>
/// Creates <see cref="IAsyncEnumerable"/> adapter for <see cref="IEnumerable"/>
/// </summary>
/// <param name="enumerable">The instance of <see cref="IEnumerable"/> to convert</param>
/// <param name="runSynchronously">If True the enumeration will be performed on the same thread, otherwise the MoveNext will be executed on a separate thread with Task.Run method</param>
/// <returns>Returns an instance of <see cref="IAsyncEnumerable"/> implementation</returns>
public static IAsyncEnumerable ToAsyncEnumerable(this IEnumerable enumerable, bool runSynchronously = true)
{
if (enumerable == null)
throw new ArgumentNullException(nameof(enumerable));
return enumerable as IAsyncEnumerable ?? new AsyncEnumerableWrapper<object>(enumerable.Cast<object>(), runSynchronously);
}
}
#endif
}
namespace Dasync.Collections
{
/// <summary>
/// Converts generic IEnumerable to IAsyncEnumerable
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static class GenericEnumerableExtensions
{
/// <summary>
/// Creates <see cref="IAsyncEnumerable{T}"/> adapter for <see cref="IEnumerable{T}"/>
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="enumerable">The instance of <see cref="IEnumerable{T}"/> to convert</param>
/// <param name="runSynchronously">If True the enumeration will be performed on the same thread, otherwise the MoveNext will be executed on a separate thread with Task.Run method</param>
/// <returns>Returns an instance of <see cref="IAsyncEnumerable{T}"/> implementation</returns>
public static IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerable<T> enumerable, bool runSynchronously = true)
{
if (enumerable == null)
throw new ArgumentNullException(nameof(enumerable));
if (ReferenceEquals(enumerable, Enumerable.Empty<T>()))
return AsyncEnumerable<T>.Empty;
return enumerable as IAsyncEnumerable<T> ?? new AsyncEnumerableWrapper<T>(enumerable, runSynchronously);
}
/// <summary>
/// Creates <see cref="IAsyncEnumerator{T}"/> adapter for the enumerator of <see cref="IEnumerable{T}"/>
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="enumerable">The instance of <see cref="IEnumerable{T}"/> to convert</param>
/// <param name="runSynchronously">If True the enumeration will be performed on the same thread, otherwise the MoveNext will be executed on a separate thread with Task.Run method</param>
/// <returns>Returns an instance of <see cref="IAsyncEnumerable{T}"/> implementation</returns>
public static IAsyncEnumerator<T> GetAsyncEnumerator<T>(this IEnumerable<T> enumerable, bool runSynchronously = true)
{
if (enumerable == null)
throw new ArgumentNullException(nameof(enumerable));
if (enumerable is IAsyncEnumerable<T> asyncEnumerable)
return asyncEnumerable.GetAsyncEnumerator();
var enumerator = enumerable.GetEnumerator();
return new AsyncEnumeratorWrapper<T>(enumerator, runSynchronously);
}
/// <summary>
/// Creates <see cref="IAsyncEnumerator{T}"/> adapter for <see cref="IEnumerator{T}"/>
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="enumerator">The instance of <see cref="IEnumerator{T}"/> to convert</param>
/// <param name="runSynchronously">If True the enumeration will be performed on the same thread, otherwise the MoveNext will be executed on a separate thread with Task.Run method</param>
/// <returns>Returns an instance of <see cref="IAsyncEnumerator{T}"/> implementation</returns>
public static IAsyncEnumerator<T> ToAsyncEnumerator<T>(this IEnumerator<T> enumerator, bool runSynchronously = true)
{
if (enumerator == null)
throw new ArgumentNullException(nameof(enumerator));
return enumerator as IAsyncEnumerator<T> ?? new AsyncEnumeratorWrapper<T>(enumerator, runSynchronously);
}
}
}
namespace Dasync.Collections
{
/// <summary>
/// Extension methods for <see cref="IAsyncEnumerable{T}"/> for backward compatibility with version 1 of this libraray.
/// Not recommended to use.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static class AsyncEnumerableAdapterExtensions
{
#if !NETSTANDARD2_1 && !NETSTANDARD2_0 && !NET461
/// <summary>
/// Converts <see cref="IAsyncEnumerable"/> to <see cref="IEnumerable"/>.
/// This method is marked as [Obsolete] to discourage you from doing such conversion,
/// which defeats the whole purpose of having a non-blocking async enumeration,
/// and what might lead to dead-locks in ASP.NET or WPF applications.
/// </summary>
[Obsolete]
public static IEnumerable ToEnumerable(this IAsyncEnumerable asyncEnumerable)
{
if (asyncEnumerable == null)
throw new ArgumentNullException(nameof(asyncEnumerable));
if (asyncEnumerable is IEnumerable enumerable)
return enumerable;
return new EnumerableAdapter(asyncEnumerable);
}
/// <summary>
/// Converts <see cref="IAsyncEnumerator"/> to <see cref="IEnumerator"/>.
/// This method is marked as [Obsolete] to discourage you from doing such conversion,
/// which defeats the whole purpose of having a non-blocking async enumeration,
/// and what might lead to dead-locks in ASP.NET or WPF applications.
/// </summary>
[Obsolete]
public static IEnumerator ToEnumerator(this IAsyncEnumerator asyncEnumerator)
{
if (asyncEnumerator == null)
throw new ArgumentNullException(nameof(asyncEnumerator));
if (asyncEnumerator is IEnumerator enumerator)
return enumerator;
return new EnumeratorAdapter(asyncEnumerator);
}
/// <summary>
/// Creates an enumerator that iterates through a collection synchronously.
/// This method is marked as [Obsolete] to discourage you from using this synchronous version of
/// the method instead of <see cref="IAsyncEnumerable.GetAsyncEnumerator(CancellationToken)"/>,
/// what might lead to dead-locks in ASP.NET or WPF applications.
/// </summary>
[Obsolete]
public static IEnumerator GetEnumerator(this IAsyncEnumerable asyncEnumerable)
{
if (asyncEnumerable == null)
throw new ArgumentNullException(nameof(asyncEnumerable));
return asyncEnumerable.GetAsyncEnumerator().ToEnumerator();
}
/// <summary>
/// Advances the enumerator to the next element of the collection synchronously.
/// This method is marked as [Obsolete] to discourage you from using this synchronous version of
/// the method instead of <see cref="IAsyncEnumerator.MoveNextAsync()"/>,
/// what might lead to dead-locks in ASP.NET or WPF applications.
/// </summary>
[Obsolete]
public static bool MoveNext(this IAsyncEnumerator asyncEnumerator)
{
if (asyncEnumerator == null)
throw new ArgumentNullException(nameof(asyncEnumerator));
return asyncEnumerator.MoveNextAsync().GetAwaiter().GetResult();
}
#endif
/// <summary>
/// Converts <see cref="IAsyncEnumerable{T}"/> to <see cref="IEnumerable{T}"/>.
/// This method is marked as [Obsolete] to discourage you from doing such conversion,
/// which defeats the whole purpose of having a non-blocking async enumeration,
/// and what might lead to dead-locks in ASP.NET or WPF applications.
/// </summary>
[Obsolete]
public static IEnumerable<T> ToEnumerable<T>(this IAsyncEnumerable<T> asyncEnumerable)
{
if (asyncEnumerable == null)
throw new ArgumentNullException(nameof(asyncEnumerable));
if (asyncEnumerable is IEnumerable<T> enumerable)
return enumerable;
return new EnumerableAdapter<T>(asyncEnumerable);
}
/// <summary>
/// Converts <see cref="IAsyncEnumerator{T}"/> to <see cref="IEnumerator{T}"/>.
/// This method is marked as [Obsolete] to discourage you from doing such conversion,
/// which defeats the whole purpose of having a non-blocking async enumeration,
/// and what might lead to dead-locks in ASP.NET or WPF applications.
/// </summary>
[Obsolete]
public static IEnumerator<T> ToEnumerator<T>(this IAsyncEnumerator<T> asyncEnumerator)
{
if (asyncEnumerator == null)
throw new ArgumentNullException(nameof(asyncEnumerator));
if (asyncEnumerator is IEnumerator<T> enumerator)
return enumerator;
return new EnumeratorAdapter<T>(asyncEnumerator);
}
/// <summary>
/// Creates an enumerator that iterates through a collection synchronously.
/// This method is marked as [Obsolete] to discourage you from using this synchronous version of
/// the method instead of <see cref="IAsyncEnumerable{T}.GetAsyncEnumerator(CancellationToken)"/>,
/// what might lead to dead-locks in ASP.NET or WPF applications.
/// </summary>
[Obsolete]
public static IEnumerator<T> GetEnumerator<T>(this IAsyncEnumerable<T> asyncEnumerable)
{
if (asyncEnumerable == null)
throw new ArgumentNullException(nameof(asyncEnumerable));
return asyncEnumerable.GetAsyncEnumerator().ToEnumerator();
}
}
}