Browse Source

Add Zip with ValueTuple return type.

Bart De Smet 6 năm trước cách đây
mục cha
commit
5da0a5aa07

+ 1 - 1
Ix.NET/Source/Directory.build.targets

@@ -14,7 +14,7 @@
     <DefineConstants>$(DefineConstants);USE_ASYNC_ITERATOR</DefineConstants>
   </PropertyGroup>
   <PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0' or '$(TargetFramework)' == 'netstandard2.1'">
-    <DefineConstants>$(DefineConstants);USE_ASYNC_ITERATOR;HAS_ASYNCENUMERABLE;HAS_ASYNCDISPOSABLE;BCL_HAS_CONFIGUREAWAIT</DefineConstants>
+    <DefineConstants>$(DefineConstants);USE_ASYNC_ITERATOR;HAS_ASYNCENUMERABLE;HAS_ASYNCDISPOSABLE;BCL_HAS_CONFIGUREAWAIT;HAS_VALUETUPLE</DefineConstants>
   </PropertyGroup>
 
   <PropertyGroup>

+ 16 - 0
Ix.NET/Source/System.Linq.Async.Queryable/System/Linq/AsyncQueryable.cs

@@ -34,6 +34,22 @@ namespace System.Linq
             return new AsyncEnumerableQuery<TElement>(source);
         }
 
+#if HAS_VALUETUPLE
+        public static IAsyncQueryable<(TFirst First, TSecond Second)> Zip<TFirst, TSecond>(this IAsyncQueryable<TFirst> first, IAsyncEnumerable<TSecond> second)
+        {
+            if (first == null)
+                throw new ArgumentNullException(nameof(first));
+            if (second == null)
+                throw new ArgumentNullException(nameof(second));
+
+#if CRIPPLED_REFLECTION
+            return first.Provider.CreateQuery<(TFirst, TSecond)>(Expression.Call(InfoOf(() => AsyncQueryable.Zip<TFirst, TSecond>(default(IAsyncQueryable<TFirst>), default(IAsyncEnumerable<TSecond>))), first.Expression, GetSourceExpression(second)));
+#else
+            return first.Provider.CreateQuery<(TFirst, TSecond)>(Expression.Call(((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(typeof(TFirst), typeof(TSecond)), first.Expression, GetSourceExpression(second)));
+#endif
+        }
+#endif
+
         private static Expression GetSourceExpression<TSource>(IAsyncEnumerable<TSource> source)
         {
             if (source is IAsyncQueryable<TSource> queryable)

+ 30 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Zip.cs

@@ -11,6 +11,36 @@ namespace System.Linq
 {
     public static partial class AsyncEnumerable
     {
+#if HAS_VALUETUPLE
+        public static IAsyncEnumerable<(TFirst First, TSecond Second)> Zip<TFirst, TSecond>(this IAsyncEnumerable<TFirst> first, IAsyncEnumerable<TSecond> second)
+        {
+            if (first == null)
+                throw Error.ArgumentNull(nameof(first));
+            if (second == null)
+                throw Error.ArgumentNull(nameof(second));
+
+#if USE_ASYNC_ITERATOR
+            return Create(Core);
+
+            async IAsyncEnumerator<(TFirst, TSecond)> Core(CancellationToken cancellationToken)
+            {
+                await using (var e1 = first.GetConfiguredAsyncEnumerator(cancellationToken, false))
+                {
+                    await using (var e2 = second.GetConfiguredAsyncEnumerator(cancellationToken, false))
+                    {
+                        while (await e1.MoveNextAsync() && await e2.MoveNextAsync())
+                        {
+                            yield return (e1.Current, e2.Current);
+                        }
+                    }
+                }
+            }
+#else
+            return new ZipAsyncIterator<TFirst, TSecond, (TFirst, TSecond)>(first, second, (first, second) => (first, second));
+#endif
+        }
+#endif
+
         public static IAsyncEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IAsyncEnumerable<TFirst> first, IAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector)
         {
             if (first == null)