public sealed class Result<T, TF>
private readonly T SuccessValue;
private readonly TF FailureValue;
public readonly bool IsSuccess;
private Result(T sv, TF fv, bool isSuccess)
public static Result<T, TF> Success(T sv) =>
new Result<T, TF>(sv, default(TF), true);
public static Result<T, TF> Failure(TF fv) =>
new Result<T, TF>(default(T), fv, false);
public Result<TResult, TF> Map<TResult>(Func<T, TResult> f) =>
? Result<TResult, TF>.Success(f(SuccessValue))
: Result<TResult, TF>.Failure(FailureValue);
public Result<U, TF> Bind<U>(Func<T, Result<U, TF>> f) =>
: Result<U, TF>.Failure(FailureValue);
public U Match<U>(Func<T, U> onSuccess, Func<TF, U> onFailure) =>
? onSuccess(SuccessValue)
: onFailure(FailureValue);
: throw new Exception($"Result is failure: \"{FailureValue}\"");
public Result<U, TF> Select<U>(Func<T, U> f) => Map(f);
public Result<U, TF> SelectMany<U>(Func<T, Result<U, TF>> f) => Bind(f);
public Result<U, TF> SelectMany<TT, U>(Func<T, Result<TT, TF>> f, Func<T, TT, U> g) => SelectMany(x => f(x).Select(y => g(x, y)));
public override string ToString() =>
? $"Success ({SuccessValue})"
: $"Failure ({FailureValue})";
public sealed class DomainType
public override string ToString() => $"DomainType ({Value})";
public readonly int Value;
public sealed class AggregateType
public AggregateType(DomainType v1, DomainType v2, DomainType v3, DomainType v4)
Values = new[] { v1, v2, v3, v4 };
public override string ToString() => $"AggregateType ([{string.Join(',', Values.Select(v => v.Value))}])";
public readonly DomainType[] Values;
public static Result<DomainType, string> TryParseDomainType(string str)
Console.WriteLine($"Trying to parse \"{str}\"");
int.TryParse(str, out var v)
? Result<DomainType, string>.Success(new DomainType(v))
: Result<DomainType, string>.Failure($"Couldn't parse an int from string \"{str}\".");
public static Result<int, string> TryParseDomainType2(string str)
Console.WriteLine($"Trying to parse \"{str}\"");
int.TryParse(str, out var v)
? Result<int, string>.Success(v)
: Result<int, string>.Failure($"Couldn't parse an int from string \"{str}\".");
public static void Main()
var aggregateTypeResult =
new AggregateType(v1, v2, v3, v4)))));
Console.WriteLine($"{nameof(aggregateTypeResult)} = {aggregateTypeResult}");
var aggregateTypeResultLinq =
from v1 in TryParseDomainType(str1)
from v2 in TryParseDomainType(str2)
from v3 in TryParseDomainType(str3)
from v4 in TryParseDomainType(str4)
select new AggregateType(v1, v2, v3, v4);
Console.WriteLine($"{nameof(aggregateTypeResultLinq)} = {aggregateTypeResultLinq}");