From 040f6d9759be4f2046f699a9c1dd7a380941885c Mon Sep 17 00:00:00 2001 From: Sanchime Date: Tue, 3 May 2022 11:07:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BATask=E6=89=A9=E5=B1=95Linq?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sanchime.Functional/Core/Extensions/Task.cs | 93 ++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/Sanchime.Functional/Core/Extensions/Task.cs b/Sanchime.Functional/Core/Extensions/Task.cs index 07fa211..5b4871a 100644 --- a/Sanchime.Functional/Core/Extensions/Task.cs +++ b/Sanchime.Functional/Core/Extensions/Task.cs @@ -1,4 +1,7 @@ +using System.Collections.Generic; using System; +using System.Threading.Tasks; +using Sanchime.Functional.Core.Products; namespace Sanchime.Functional.Core.Extensions; public static class TaskExtension @@ -9,7 +12,9 @@ public static class TaskExtension #region 函子 public static Task Map(this Task @this, Func Faulted, Func Completed) - => @this.ContinueWith(val => val.Status == TaskStatus.Faulted ? Faulted(val.Exception!) : Completed(val.Result)); + => @this.ContinueWith(val => val.Status == TaskStatus.Faulted + ? Faulted(val.Exception!) + : Completed(val.Result)); public static async Task Map(this Task @this, Func mapping) => mapping(await @this.ConfigureAwait(false)); @@ -22,16 +27,102 @@ public static class TaskExtension public static Task> Map(this Task @this, Func mapping) => @this.Map(mapping.Curry()); + #endregion + + #region 单子 + public static async Task Bind(this Task @this, Func> binding) + => await binding(await @this.ConfigureAwait(false)).ConfigureAwait(false); #endregion + #region 应用子 public static async Task Apply(this Task> @this, Task task) => (await @this.ConfigureAwait(false))(await task.ConfigureAwait(false)); public static Task> Apply(this Task> @this, Task task) => @this.Map(CurryingExtension.Curry).Apply(task); + #endregion + public static Task OrElse(this Task @this, Func> fallback) + => @this.ContinueWith(task => task.Status == TaskStatus.Faulted + ? fallback() + : Task.FromResult(task.Result)) + .Unwrap(); + + public static Task Recover(this Task @this, Func fallback) + => @this.ContinueWith(task => task.Status == TaskStatus.Faulted + ? fallback(task.Exception!) + : task.Result); + public static Task RecoverWith(this Task @this, Func> fallback) + => @this.ContinueWith(task => task.Status == TaskStatus.Faulted + ? fallback(task.Exception!) + : Task.FromResult(task.Result)) + .Unwrap(); + + public static Task ForEach(this Task @this, Action continuaction) + => @this.ContinueWith(task => continuaction.ToFunc()(task.Result), TaskContinuationOptions.OnlyOnRanToCompletion); + + #region Linq式 + public static async Task SelectMany(this Task source, Func> binding, Func project) + { + var task = await source; + var result = await binding(task); + return project(task, result); + } + + public static async Task SelectMany(this Task source, Func> binding, Func project) + { + var task = await source; + var result = await binding(task); + return project(task, result); + } + + public static async Task SelectMany(this Task source, Func> binding, Func project) + { + await source; + var result = await binding(Unit.Value); + return project(Unit.Value, result); + } + + public static async Task SelectMany(this Task source, Func> binding) + => await binding(await source.ConfigureAwait(false)).ConfigureAwait(false); + + public static async Task Select(this Task source, Func mapping) + => mapping(await source); + + public static async Task Where(this Task source, Func predicate) + { + var task = await source; + if (!predicate(task)) + { + throw new OperationCanceledException(); + } + return task; + } + + public static async Task Join(this Task source, Task inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector) + { + await Task.WhenAll(source, inner); + + if (!EqualityComparer.Default.Equals(outerKeySelector(source.Result), innerKeySelector(inner.Result))) + { + throw new OperationCanceledException(); + } + + return resultSelector(source.Result, inner.Result); + } + + public static async Task GroupJoin(this Task source, Task inner, Func outerKeySelector, Func innerKeySelector, Func, V> resultSelector) + { + var task = await source; + return resultSelector(task, + inner.Where(u => EqualityComparer.Default.Equals( + outerKeySelector(task), innerKeySelector(u)))); + } + + #endregion + }