namespace MS.Microservice.Core.Functional
{
///
/// Either 的核心组合能力。
///
public static partial class EitherExtensions
{
public static Task> AsTask(this Either either)
=> Task.FromResult(either);
public static Task> RightAsync(R value)
=> Task.FromResult((Either)F.Right(value));
public static Task> LeftAsync(L value)
=> Task.FromResult((Either)F.Left(value));
public static Either Try(Func operation, string code = "unexpected")
{
try
{
return F.Right(operation());
}
catch (Exception ex)
{
return F.Left(Error.FromException(ex, code));
}
}
public static Either Try(Action operation, string code = "unexpected")
=> Try(() =>
{
operation();
return Unit.Default;
}, code);
public static async Task> TryAsync(Func> operation, string code = "unexpected")
{
try
{
return F.Right(await operation());
}
catch (Exception ex)
{
return F.Left(Error.FromException(ex, code));
}
}
public static Task> TryAsync(Func operation, string code = "unexpected")
=> TryAsync(async () =>
{
await operation();
return Unit.Default;
}, code);
public static async Task> Map(this Task> eitherTask, Func mapper)
=> (await eitherTask).Map(mapper);
public static async Task> MapLeft(this Task> eitherTask, Func mapper)
=> (await eitherTask).MapLeft(mapper);
public static async Task> Bind(this Task> eitherTask, Func> binder)
=> (await eitherTask).Bind(binder);
public static async Task> BindAsync(this Task> eitherTask, Func>> binder)
{
var either = await eitherTask;
return await either.BindAsync(binder);
}
public static async Task> MapAsync(this Task> eitherTask, Func> mapper)
{
var either = await eitherTask;
return await either.MapAsync(mapper);
}
public static async Task> Tap(this Task> eitherTask, Action effect)
=> (await eitherTask).Tap(effect);
public static async Task> TapAsync(this Task> eitherTask, Func effect)
{
var either = await eitherTask;
return await either.TapAsync(effect);
}
public static async Task> Where(this Task> eitherTask, Func predicate, Func leftFactory)
=> (await eitherTask).Where(predicate, leftFactory);
public static async Task MatchAsync(this Task> eitherTask, Func> left, Func> right)
=> await (await eitherTask).MatchAsync(left, right);
public static async Task MatchAsync(this Task> eitherTask, Func left, Func right)
=> (await eitherTask).Match(left, right);
extension(Either either)
{
public Either Map(Func left, Func right)
=> either.Match>(
left: l => F.Left(left(l)),
right: r => F.Right(right(r)));
public Either Map(Func mapper)
=> either.Match>(
left: l => F.Left(l),
right: r => F.Right(mapper(r)));
public Either MapLeft(Func mapper)
=> either.Match>(
left: l => F.Left(mapper(l)),
right: r => F.Right(r));
public Either Bind(Func> binder)
=> either.Match>(
left: l => F.Left(l),
right: binder);
public Task> BindAsync(Func>> binder)
=> either.Match(
left: l => Task.FromResult((Either)F.Left(l)),
right: binder);
public Task> MapAsync(Func> mapper)
=> either.Match>>(
left: l => Task.FromResult((Either)F.Left(l)),
right: async r => F.Right(await mapper(r)));
public Either Tap(Action effect)
{
if (either.IsRight)
{
effect(either.Right);
}
return either;
}
public async Task> TapAsync(Func effect)
{
if (either.IsRight)
{
await effect(either.Right);
}
return either;
}
public R GetOrElse(R fallback)
=> either.Match(
left: _ => fallback,
right: r => r);
public R GetOrElse(Func fallback)
=> either.Match(
left: fallback,
right: r => r);
public Either OrElse(Either fallback)
=> either.Match(
left: _ => fallback,
right: _ => either);
public Either Where(Func predicate, Func leftFactory)
=> either.Match>(
left: l => F.Left(l),
right: r => predicate(r)
? F.Right(r)
: F.Left(leftFactory(r)));
public Task MatchAsync(Func> left, Func> right)
=> either.Match(left, right);
public Either Select(Func mapper)
=> either.Map(mapper);
public Either SelectMany(Func> bind, Func project)
=> either.Bind(r => bind(r).Map(r2 => project(r, r2)));
}
}
}