diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..9048b8f
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,83 @@
+name: Build
+on:
+ push:
+ branches:
+ - master
+ tags:
+ - "*"
+ pull_request:
+jobs:
+ calculate-version:
+ runs-on: ubuntu-20.04
+ outputs:
+ version: ${{ steps.version.outputs.version }}
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@master
+ with:
+ fetch-depth: 0
+ - name: Install GitVersion
+ uses: gittools/actions/gitversion/setup@v0.9.11
+ with:
+ versionSpec: "5.8.1"
+ - name: Run GitVersion
+ id: gitversion
+ uses: gittools/actions/gitversion/execute@v0.9.11
+ - name: Version
+ id: version
+ run: |
+ version=${{ steps.gitversion.outputs.nuGetVersionV2 }}
+ if [ "${{ github.event_name }}" == "pull_request" ]
+ then
+ version=${version}-${{ steps.gitversion.outputs.shortSha }}
+ fi
+ echo "::set-output name=version::${version}"
+ build:
+ runs-on: ${{ matrix.os }}
+ needs: [calculate-version]
+ strategy:
+ matrix:
+ include:
+ - os: ubuntu-20.04
+ nugetPush: false
+ - os: windows-2019
+ nugetPush: true
+ - os: macos-10.15
+ nugetPush: false
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@master
+ with:
+ fetch-depth: 0
+ submodules: recursive
+ - name: Setup dotnet SDK
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "6.0.101"
+ - name: Build
+ run: |
+ dotnet build -c Release -p:Version=${{ needs.calculate-version.outputs.version }}
+ shell: bash
+ - name: Test
+ run: dotnet test -c Release --no-build
+ shell: bash
+ - name: Archive NuGet Packages
+ uses: actions/upload-artifact@v2
+ if: ${{ matrix.nugetPush }}
+ with:
+ name: packages
+ path: |
+ **/*.nupkg
+ **/*.snupkg
+ retention-days: 1
+ nuget-push:
+ runs-on: ubuntu-20.04
+ needs: [build]
+ if: github.event_name != 'pull_request'
+ steps:
+ - name: Download NuGet Packages
+ uses: actions/download-artifact@v2
+ with:
+ name: packages
+ - name: NuGet Push
+ run: dotnet nuget push **/*.nupkg -s https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index d925c91..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-language: csharp
-branches:
- except:
- - /^[0-9]/
-env:
- global:
- - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
- - DOTNET_CLI_TELEMETRY_OPTOUT: 1
-jobs:
- include:
- - os: linux
- dist: bionic
- dotnet: 3.1
- - os: osx
- osx_image: xcode11.2
- dotnet: 3.1.301
- before_install:
- - ulimit -n 4096
-script:
- - dotnet build -c Release
- - dotnet test -c Release --no-build
diff --git a/Directory.Build.props b/Directory.Build.props
index 35c21b0..cddbb5f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,9 +2,9 @@
Winton
Winton
- Copyright 2020 Winton
+ Copyright 2022 Winton
$(MSBuildThisFileDirectory)Rules.ruleset
- 8.0
+ 10.0
enable
True
diff --git a/LICENSE b/LICENSE
index 963067d..087418a 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright 2018 Winton
+Copyright 2022 Winton
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index a712b99..c4c9bf6 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,11 @@
# Winton.DomainModelling.Abstractions
-[![Appveyor](https://ci.appveyor.com/api/projects/status/7mba8m947ed603r1?svg=true)](https://ci.appveyor.com/project/wintoncode/winton-domainmodelling-abstractions/branch/master)
-[![Travis CI](https://travis-ci.com/wintoncode/Winton.DomainModelling.Abstractions.svg?branch=master)](https://travis-ci.com/wintoncode/Winton.DomainModelling.Abstractions)
-[![NuGet version](https://img.shields.io/nuget/v/Winton.DomainModelling.Abstractions.svg)](https://www.nuget.org/packages/Winton.DomainModelling.Abstractions)
-[![NuGet version](https://img.shields.io/nuget/vpre/Winton.DomainModelling.Abstractions.svg)](https://www.nuget.org/packages/Winton.DomainModelling.Abstractions)
-
Abstractions useful for modelling a domain.
+[![NuGet Badge](https://buildstats.info/nuget/Winton.DomainModelling.Abstractions)](https://www.nuget.org/packages/Winton.DomainModelling.Abstractions/)
+
+[![Build history](https://buildstats.info/github/chart/wintoncode/Winton.DomainModelling.Abstractions?branch=master)](https://github.com/wintoncode/Winton.DomainModelling.Abstractions/actions)
+
## Building blocks
### `Entity`
@@ -16,7 +15,7 @@ Instances are equal if their IDs are equal. Any equatable ID type can be used.
## Results
-### `Result`
+### `Result`
Represents the result of a domain operation that returns data of type `TData`. It is an abstract type with exactly two concretions: `Success` and `Failure`. It is a specialisation of the more generic `Either` type found in functional programming and is inspired by [Scott Wlaschin's Railway Oriented Programming](https://fsharpforfunandprofit.com/rop/) in F#.
@@ -41,6 +40,7 @@ public Person GetAdult(int id)
```
This implementation has two major drawbacks:
+
1) From a client's perspective, the API is not expressive enough. The method signature gives no indication that it might throw, so the client would need to peek inside to find that out.
2) From an implementer's perspective, the error checking, whilst simple enough in this example, can often grow quite complex. This makes the implementation of the method hard to follow due to the number of conditional branches. We may try factoring out the condition checking blocks into separate methods to solve this problem. This would also allow us to share some of this logic with other parts of the code base. These factored-out methods would then have a signature like `void CheckPersonExists(Person person)`. Again, this signature tells us nothing about the fact that the method might throw an exception. Currently, the compiler is also not able to do the flow analysis necessary to determine that the `person` is not `null` after calling such a method and so we may be left with warnings in the original call site about possible null references, even though we know we've checked for that condition.
@@ -66,7 +66,8 @@ Now we have a much more expressive method signature, which indicates that we mig
If the operation has no data to return then a `Result` can be used. `Unit` is a special type that indicates the absence of a value, because `void` is not a valid type in C#.
-Some recommendations on using `Result` types:
+Some recommendations on using `Result` types:
+
* Make all public domain methods return a `Result`. Most domain operations will have a failure case that the client should be informed about, but even if they don't, by returning `Result` now it can be easily added later without breaking the public API.
* Once an operation is in "result space", keep it there for as long as possible. `Result` has a fluent API to facilitate this. This is similar to how, once one operation becomes `async` it is best to make all surrounding operations `async` too. This can be re-phrased as, don't match on the result until the last possible moment. For example, in a web API this would mean only unwrapping the result in the Controller.
@@ -83,6 +84,7 @@ Represents a failed `Result`. When constructed it takes an `Error` which contain
Like exceptions, errors form a hierarchy, with all errors deriving from the base `Error` type. This library defines a few common domain error types, which are listed below, but it is expected that more specific errors will be defined on a per-domain basis.
Some recommendations on designing errors:
+
* Try not to create custom errors that are too granular. Model them as you would entities and use the language of the domain model to guide their creation. The concept should make sense to a domain expert.
* The title should be the same for all instances of the error. The details are where instance specific information can be provided. If you are creating a custom error, make the title static and only let clients customise the details. See implementations of errors in this library for examples.
* Only use them for domain errors. Exceptions should still be used for system failures, such as network requests, and programming errors.
diff --git a/Winton.DomainModelling.Abstractions.sln b/Winton.DomainModelling.Abstractions.sln
index 5667d46..d74fa12 100644
--- a/Winton.DomainModelling.Abstractions.sln
+++ b/Winton.DomainModelling.Abstractions.sln
@@ -6,8 +6,6 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{859C9252-D63B-4ECB-9AB5-0BA8415C76AE}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
- .travis.yml = .travis.yml
- appveyor.yml = appveyor.yml
CONTRIBUTING.md = CONTRIBUTING.md
Directory.Build.props = Directory.Build.props
GitVersion.yml = GitVersion.yml
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index e4f78c0..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-environment:
- CLI_VERSION: latest
- DOTNET_CLI_TELEMETRY_OPTOUT: 1
- DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
-image: Visual Studio 2019
-configuration:
- - Release
-before_build:
- - dotnet tool install -g GitVersion.Tool
- - dotnet gitversion /l console /output buildserver
-build_script:
- - dotnet build -c Release -p:Version=%GitVersion_NuGetVersion%
-test_script:
- - dotnet test -c Release --no-build
-artifacts:
- - name: NuGet
- path: .\**\*.nupkg
- - name: Symbols
- path: .\**\*.snupkg
-deploy:
- - provider: NuGet
- api_key:
- secure: +CD+4G+gMInD/BjNvO24NW9u1udGdsx0fUi6bh0muNezQ9fP0sHnS1f96f0OXUy6
- on:
- branch:
- - master
- - /release\/[0-9]\.[0-9]/
\ No newline at end of file
diff --git a/src/Winton.DomainModelling.Abstractions/AsyncResultExtensions.cs b/src/Winton.DomainModelling.Abstractions/AsyncResultExtensions.cs
index 8341480..32deee7 100644
--- a/src/Winton.DomainModelling.Abstractions/AsyncResultExtensions.cs
+++ b/src/Winton.DomainModelling.Abstractions/AsyncResultExtensions.cs
@@ -4,569 +4,568 @@
using System;
using System.Threading.Tasks;
-namespace Winton.DomainModelling
+namespace Winton.DomainModelling;
+
+///
+/// Extension methods for asynchronous results which make it possible to chain asynchronous results together
+/// using a fluent API in the same way as synchronous results.
+///
+public static class AsyncResultExtensions
{
///
- /// Extension methods for asynchronous results which make it possible to chain asynchronous results together
- /// using a fluent API in the same way as synchronous results.
+ /// Invokes another result generating function which takes as input the error of this result
+ /// if it is a failure after it has been awaited.
///
- public static class AsyncResultExtensions
+ ///
+ /// If this result is a success then this is a no-op and the original success is retained.
+ /// This is useful for handling errors.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The function that is invoked if this result is a failure.
+ ///
+ ///
+ /// If this result is a failure, then the result of onFailure function;
+ /// otherwise the original error.
+ ///
+ public static async Task> Catch(
+ this Task> resultTask,
+ Func> onFailure)
{
- ///
- /// Invokes another result generating function which takes as input the error of this result
- /// if it is a failure after it has been awaited.
- ///
- ///
- /// If this result is a success then this is a no-op and the original success is retained.
- /// This is useful for handling errors.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The function that is invoked if this result is a failure.
- ///
- ///
- /// If this result is a failure, then the result of onFailure function;
- /// otherwise the original error.
- ///
- public static async Task> Catch(
- this Task> resultTask,
- Func> onFailure)
- {
- Result result = await resultTask;
- return result.Catch(onFailure);
- }
+ Result result = await resultTask;
+ return result.Catch(onFailure);
+ }
- ///
- /// Invokes another result generating function which takes as input the error of this result
- /// if it is a failure after it has been awaited.
- ///
- ///
- /// If this result is a success then this is a no-op and the original success is retained.
- /// This is useful for handling errors.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The asynchronous function that is invoked if this result is a failure.
- ///
- ///
- /// If this result is a failure, then the result of onFailure function;
- /// otherwise the original error.
- ///
- public static async Task> Catch(
- this Task> resultTask,
- Func>> onFailure)
- {
- Result result = await resultTask;
- return await result.Catch(onFailure);
- }
+ ///
+ /// Invokes another result generating function which takes as input the error of this result
+ /// if it is a failure after it has been awaited.
+ ///
+ ///
+ /// If this result is a success then this is a no-op and the original success is retained.
+ /// This is useful for handling errors.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The asynchronous function that is invoked if this result is a failure.
+ ///
+ ///
+ /// If this result is a failure, then the result of onFailure function;
+ /// otherwise the original error.
+ ///
+ public static async Task> Catch(
+ this Task> resultTask,
+ Func>> onFailure)
+ {
+ Result result = await resultTask;
+ return await result.Catch(onFailure);
+ }
- ///
- /// Combines this result with another.
- /// If both are successful then combineData is invoked;
- /// else if either is a failure then combineErrors is invoked.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The type of data in the other result.
- ///
- ///
- /// The type of data in the combined result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The other result to be combined with this one.
- ///
- ///
- /// The function that is invoked to combine the data when both of the results are successful.
- ///
- ///
- /// The function that is invoked to combine the errors when either of the results is a failure.
- ///
- ///
- /// A new .
- ///
- public static async Task> Combine(
- this Task> resultTask,
- Result other,
- Func combineData,
- Func combineErrors)
- {
- Result result = await resultTask;
- return result.Combine(other, combineData, combineErrors);
- }
+ ///
+ /// Combines this result with another.
+ /// If both are successful then combineData is invoked;
+ /// else if either is a failure then combineErrors is invoked.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The type of data in the other result.
+ ///
+ ///
+ /// The type of data in the combined result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The other result to be combined with this one.
+ ///
+ ///
+ /// The function that is invoked to combine the data when both of the results are successful.
+ ///
+ ///
+ /// The function that is invoked to combine the errors when either of the results is a failure.
+ ///
+ ///
+ /// A new .
+ ///
+ public static async Task> Combine(
+ this Task> resultTask,
+ Result other,
+ Func combineData,
+ Func combineErrors)
+ {
+ Result result = await resultTask;
+ return result.Combine(other, combineData, combineErrors);
+ }
- ///
- /// Combines this result with another.
- /// If both are successful then combineData is invoked;
- /// else if either is a failure then combineErrors is invoked.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The type of data in the other result.
- ///
- ///
- /// The type of data in the combined result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The other asynchronous result to be combined with this one.
- ///
- ///
- /// The function that is invoked to combine the data when both of the results are successful.
- ///
- ///
- /// The function that is invoked to combine the errors when either of the results is a failure.
- ///
- ///
- /// A new .
- ///
- public static async Task> Combine(
- this Task> resultTask,
- Task> otherResultTask,
- Func combineData,
- Func combineErrors)
- {
- Result result = await resultTask;
- Result otherResult = await otherResultTask;
- return result.Combine(otherResult, combineData, combineErrors);
- }
+ ///
+ /// Combines this result with another.
+ /// If both are successful then combineData is invoked;
+ /// else if either is a failure then combineErrors is invoked.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The type of data in the other result.
+ ///
+ ///
+ /// The type of data in the combined result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The other asynchronous result to be combined with this one.
+ ///
+ ///
+ /// The function that is invoked to combine the data when both of the results are successful.
+ ///
+ ///
+ /// The function that is invoked to combine the errors when either of the results is a failure.
+ ///
+ ///
+ /// A new .
+ ///
+ public static async Task> Combine(
+ this Task> resultTask,
+ Task> otherResultTask,
+ Func combineData,
+ Func combineErrors)
+ {
+ Result result = await resultTask;
+ Result otherResult = await otherResultTask;
+ return result.Combine(otherResult, combineData, combineErrors);
+ }
- ///
- /// Used to match on whether this result is a success or a failure.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The type that is returned.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The function that is invoked if this result represents a success.
- ///
- ///
- /// The function that is invoked if this result represents a failure.
- ///
- ///
- /// A value that is mapped from either the data or the error.
- ///
- public static async Task Match(
- this Task> resultTask,
- Func onSuccess,
- Func onFailure)
- {
- Result result = await resultTask;
- return result.Match(onSuccess, onFailure);
- }
+ ///
+ /// Used to match on whether this result is a success or a failure.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The type that is returned.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The function that is invoked if this result represents a success.
+ ///
+ ///
+ /// The function that is invoked if this result represents a failure.
+ ///
+ ///
+ /// A value that is mapped from either the data or the error.
+ ///
+ public static async Task Match(
+ this Task> resultTask,
+ Func onSuccess,
+ Func onFailure)
+ {
+ Result result = await resultTask;
+ return result.Match(onSuccess, onFailure);
+ }
- ///
- /// Invokes the specified action if the result is a failure and returns the original result.
- ///
- ///
- /// If this result is a success then this is a no-op and the original success is retained.
- /// This is useful for publishing domain model notifications when an operation fails.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The action that will be invoked if this result is a failure.
- ///
- ///
- /// The original result.
- ///
- public static async Task> OnFailure(
- this Task> resultTask,
- Action onFailure)
- {
- return await resultTask.OnFailure(_ => onFailure());
- }
+ ///
+ /// Invokes the specified action if the result is a failure and returns the original result.
+ ///
+ ///
+ /// If this result is a success then this is a no-op and the original success is retained.
+ /// This is useful for publishing domain model notifications when an operation fails.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The action that will be invoked if this result is a failure.
+ ///
+ ///
+ /// The original result.
+ ///
+ public static async Task> OnFailure(
+ this Task> resultTask,
+ Action onFailure)
+ {
+ return await resultTask.OnFailure(_ => onFailure());
+ }
- ///
- /// Invokes the specified action if the result is a failure and returns the original result.
- ///
- ///
- /// If this result is a success then this is a no-op and the original success is retained.
- /// This is useful for publishing domain model notifications when an operation fails.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The action that will be invoked if this result is a failure.
- ///
- ///
- /// The original result.
- ///
- public static async Task> OnFailure(
- this Task> resultTask,
- Action onFailure)
- {
- Result result = await resultTask;
- return result.OnFailure(onFailure);
- }
+ ///
+ /// Invokes the specified action if the result is a failure and returns the original result.
+ ///
+ ///
+ /// If this result is a success then this is a no-op and the original success is retained.
+ /// This is useful for publishing domain model notifications when an operation fails.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The action that will be invoked if this result is a failure.
+ ///
+ ///
+ /// The original result.
+ ///
+ public static async Task> OnFailure(
+ this Task> resultTask,
+ Action onFailure)
+ {
+ Result result = await resultTask;
+ return result.OnFailure(onFailure);
+ }
- ///
- /// Invokes the specified action if the result is a failure and returns the original result.
- ///
- ///
- /// If this result is a success then this is a no-op and the original success is retained.
- /// This is useful for publishing domain model notifications when an operation fails.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The asynchronous action that will be invoked if this result is a failure.
- ///
- ///
- /// The original result.
- ///
- public static async Task> OnFailure(
- this Task> resultTask,
- Func onFailure)
- {
- return await resultTask.OnFailure(_ => onFailure());
- }
+ ///
+ /// Invokes the specified action if the result is a failure and returns the original result.
+ ///
+ ///
+ /// If this result is a success then this is a no-op and the original success is retained.
+ /// This is useful for publishing domain model notifications when an operation fails.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The asynchronous action that will be invoked if this result is a failure.
+ ///
+ ///
+ /// The original result.
+ ///
+ public static async Task> OnFailure(
+ this Task> resultTask,
+ Func onFailure)
+ {
+ return await resultTask.OnFailure(_ => onFailure());
+ }
- ///
- /// Invokes the specified action if the result is a failure and returns the original result.
- ///
- ///
- /// If this result is a success then this is a no-op and the original success is retained.
- /// This is useful for publishing domain model notifications when an operation fails.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The asynchronous action that will be invoked if this result is a failure.
- ///
- ///
- /// The original result.
- ///
- public static async Task> OnFailure(
- this Task> resultTask,
- Func onFailure)
- {
- Result result = await resultTask;
- return await result.OnFailure(onFailure);
- }
+ ///
+ /// Invokes the specified action if the result is a failure and returns the original result.
+ ///
+ ///
+ /// If this result is a success then this is a no-op and the original success is retained.
+ /// This is useful for publishing domain model notifications when an operation fails.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The asynchronous action that will be invoked if this result is a failure.
+ ///
+ ///
+ /// The original result.
+ ///
+ public static async Task> OnFailure(
+ this Task> resultTask,
+ Func onFailure)
+ {
+ Result result = await resultTask;
+ return await result.OnFailure(onFailure);
+ }
- ///
- /// Invokes the specified action if the result is a success and returns the original result.
- ///
- ///
- /// If this result is a failure then this is a no-op and the original failure is retained.
- /// This is useful for publishing domain model notifications when an operation succeeds.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The action that will be invoked if this result is a success.
- ///
- ///
- /// The original result.
- ///
- public static async Task> OnSuccess(
- this Task> resultTask,
- Action onSuccess)
- {
- return await resultTask.OnSuccess(data => onSuccess());
- }
+ ///
+ /// Invokes the specified action if the result is a success and returns the original result.
+ ///
+ ///
+ /// If this result is a failure then this is a no-op and the original failure is retained.
+ /// This is useful for publishing domain model notifications when an operation succeeds.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The action that will be invoked if this result is a success.
+ ///
+ ///
+ /// The original result.
+ ///
+ public static async Task> OnSuccess(
+ this Task> resultTask,
+ Action onSuccess)
+ {
+ return await resultTask.OnSuccess(data => onSuccess());
+ }
- ///
- /// Invokes the specified action if the result is a success and returns the original result.
- ///
- ///
- /// If this result is a failure then this is a no-op and the original failure is retained.
- /// This is useful for publishing domain model notifications when an operation succeeds.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The action that will be invoked if this result is a success.
- ///
- ///
- /// The original result.
- ///
- public static async Task> OnSuccess(
- this Task> resultTask,
- Action onSuccess)
- {
- Result result = await resultTask;
- return result.OnSuccess(onSuccess);
- }
+ ///
+ /// Invokes the specified action if the result is a success and returns the original result.
+ ///
+ ///
+ /// If this result is a failure then this is a no-op and the original failure is retained.
+ /// This is useful for publishing domain model notifications when an operation succeeds.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The action that will be invoked if this result is a success.
+ ///
+ ///
+ /// The original result.
+ ///
+ public static async Task> OnSuccess(
+ this Task> resultTask,
+ Action onSuccess)
+ {
+ Result result = await resultTask;
+ return result.OnSuccess(onSuccess);
+ }
- ///
- /// Invokes the specified action if the result is a success and returns the original result.
- ///
- ///
- /// If this result is a failure then this is a no-op and the original failure is retained.
- /// This is useful for publishing domain model notifications when an operation succeeds.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The asynchronous action that will be invoked if this result is a success.
- ///
- ///
- /// The original result.
- ///
- public static async Task> OnSuccess(
- this Task> resultTask,
- Func onSuccess)
- {
- return await resultTask.OnSuccess(data => onSuccess());
- }
+ ///
+ /// Invokes the specified action if the result is a success and returns the original result.
+ ///
+ ///
+ /// If this result is a failure then this is a no-op and the original failure is retained.
+ /// This is useful for publishing domain model notifications when an operation succeeds.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The asynchronous action that will be invoked if this result is a success.
+ ///
+ ///
+ /// The original result.
+ ///
+ public static async Task> OnSuccess(
+ this Task> resultTask,
+ Func onSuccess)
+ {
+ return await resultTask.OnSuccess(data => onSuccess());
+ }
- ///
- /// Invokes the specified action if the result is a success and returns the original result.
- ///
- ///
- /// If this result is a failure then this is a no-op and the original failure is retained.
- /// This is useful for publishing domain model notifications when an operation succeeds.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The asynchronous action that will be invoked if this result is a success.
- ///
- ///
- /// The original result.
- ///
- public static async Task> OnSuccess(
- this Task> resultTask,
- Func onSuccess)
- {
- Result result = await resultTask;
- return await result.OnSuccess(onSuccess);
- }
+ ///
+ /// Invokes the specified action if the result is a success and returns the original result.
+ ///
+ ///
+ /// If this result is a failure then this is a no-op and the original failure is retained.
+ /// This is useful for publishing domain model notifications when an operation succeeds.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The asynchronous action that will be invoked if this result is a success.
+ ///
+ ///
+ /// The original result.
+ ///
+ public static async Task> OnSuccess(
+ this Task> resultTask,
+ Func onSuccess)
+ {
+ Result result = await resultTask;
+ return await result.OnSuccess(onSuccess);
+ }
- ///
- /// Projects a successful result's data from one type to another.
- ///
- ///
- /// If this result is a failure then this is a no-op.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The type of data in the new result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The function that is invoked to select the data.
- ///
- ///
- /// A new result containing either; the output of the selector function
- /// if this result is a success, otherwise the original failure.
- ///
- public static async Task> Select(
- this Task> resultTask,
- Func selector)
- {
- Result result = await resultTask;
- return result.Select(selector);
- }
+ ///
+ /// Projects a successful result's data from one type to another.
+ ///
+ ///
+ /// If this result is a failure then this is a no-op.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The type of data in the new result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The function that is invoked to select the data.
+ ///
+ ///
+ /// A new result containing either; the output of the selector function
+ /// if this result is a success, otherwise the original failure.
+ ///
+ public static async Task> Select(
+ this Task> resultTask,
+ Func selector)
+ {
+ Result result = await resultTask;
+ return result.Select(selector);
+ }
- ///
- /// Projects a successful result's data from one type to another.
- ///
- ///
- /// If this result is a failure then this is a no-op.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The type of data in the new result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The asynchronous function that is invoked to select the data.
- ///
- ///
- /// A new result containing either; the output of the selector function
- /// if this result is a success, otherwise the original failure.
- ///
- public static async Task> Select(
- this Task> resultTask,
- Func> selector)
- {
- Result result = await resultTask;
- return await result.Select(selector);
- }
+ ///
+ /// Projects a successful result's data from one type to another.
+ ///
+ ///
+ /// If this result is a failure then this is a no-op.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The type of data in the new result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The asynchronous function that is invoked to select the data.
+ ///
+ ///
+ /// A new result containing either; the output of the selector function
+ /// if this result is a success, otherwise the original failure.
+ ///
+ public static async Task> Select(
+ this Task> resultTask,
+ Func> selector)
+ {
+ Result result = await resultTask;
+ return await result.Select(selector);
+ }
- ///
- /// Projects a failed result's data from one type to another.
- ///
- ///
- /// If this result is a success then this is a no-op.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The function that is invoked to select the error.
- ///
- ///
- /// A new result containing either; the output of the selector function
- /// if this result is a failure, otherwise the original success.
- ///
- public static async Task> SelectError(
- this Task> resultTask,
- Func selector)
- {
- Result result = await resultTask;
- return result.SelectError(selector);
- }
+ ///
+ /// Projects a failed result's data from one type to another.
+ ///
+ ///
+ /// If this result is a success then this is a no-op.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The function that is invoked to select the error.
+ ///
+ ///
+ /// A new result containing either; the output of the selector function
+ /// if this result is a failure, otherwise the original success.
+ ///
+ public static async Task> SelectError(
+ this Task> resultTask,
+ Func selector)
+ {
+ Result result = await resultTask;
+ return result.SelectError(selector);
+ }
- ///
- /// Projects a failed result's error from one type to another.
- ///
- ///
- /// If this result is a success then this is a no-op.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The asynchronous function that is invoked to select the error.
- ///
- ///
- /// A new result containing either; the output of the selector function
- /// if this result is a failure, otherwise the original success.
- ///
- public static async Task> SelectError(
- this Task> resultTask,
- Func> selector)
- {
- Result result = await resultTask;
- return await result.SelectError(selector);
- }
+ ///
+ /// Projects a failed result's error from one type to another.
+ ///
+ ///
+ /// If this result is a success then this is a no-op.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The asynchronous function that is invoked to select the error.
+ ///
+ ///
+ /// A new result containing either; the output of the selector function
+ /// if this result is a failure, otherwise the original success.
+ ///
+ public static async Task> SelectError(
+ this Task> resultTask,
+ Func> selector)
+ {
+ Result result = await resultTask;
+ return await result.SelectError(selector);
+ }
- ///
- /// Invokes another result generating function which takes as input the data of this result
- /// if it is a success after it has been awaited.
- ///
- ///
- /// If this result is a failure then this is a no-op and the original failure is retained.
- /// This is useful for chaining serial operations together that return results.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The type of data in the new result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The function that is invoked if this result is a success.
- ///
- ///
- /// If this result is a success, then the result of onSuccess function;
- /// otherwise the original error.
- ///
- public static async Task> Then(
- this Task> resultTask,
- Func> onSuccess)
- {
- Result result = await resultTask;
- return result.Then(onSuccess);
- }
+ ///
+ /// Invokes another result generating function which takes as input the data of this result
+ /// if it is a success after it has been awaited.
+ ///
+ ///
+ /// If this result is a failure then this is a no-op and the original failure is retained.
+ /// This is useful for chaining serial operations together that return results.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The type of data in the new result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The function that is invoked if this result is a success.
+ ///
+ ///
+ /// If this result is a success, then the result of onSuccess function;
+ /// otherwise the original error.
+ ///
+ public static async Task> Then(
+ this Task> resultTask,
+ Func> onSuccess)
+ {
+ Result result = await resultTask;
+ return result.Then(onSuccess);
+ }
- ///
- /// Invokes another result generating function which takes as input the data of this result
- /// if it is a success after it has been awaited.
- ///
- ///
- /// If this result is a failure then this is a no-op and the original failure is retained.
- /// This is useful for chaining serial operations together that return results.
- ///
- ///
- /// The type of data encapsulated by the result.
- ///
- ///
- /// The type of data in the new result.
- ///
- ///
- /// The asynchronous result that this extension method is invoked on.
- ///
- ///
- /// The asynchronous function that is invoked if this result is a success.
- ///
- ///
- /// If this result is a success, then the result of onSuccess function;
- /// otherwise the original error.
- ///
- public static async Task> Then(
- this Task> resultTask,
- Func>> onSuccess)
- {
- Result result = await resultTask;
- return await result.Then(onSuccess);
- }
+ ///
+ /// Invokes another result generating function which takes as input the data of this result
+ /// if it is a success after it has been awaited.
+ ///
+ ///
+ /// If this result is a failure then this is a no-op and the original failure is retained.
+ /// This is useful for chaining serial operations together that return results.
+ ///
+ ///
+ /// The type of data encapsulated by the result.
+ ///
+ ///
+ /// The type of data in the new result.
+ ///
+ ///
+ /// The asynchronous result that this extension method is invoked on.
+ ///
+ ///
+ /// The asynchronous function that is invoked if this result is a success.
+ ///
+ ///
+ /// If this result is a success, then the result of onSuccess function;
+ /// otherwise the original error.
+ ///
+ public static async Task> Then(
+ this Task> resultTask,
+ Func>> onSuccess)
+ {
+ Result result = await resultTask;
+ return await result.Then(onSuccess);
}
}
\ No newline at end of file
diff --git a/src/Winton.DomainModelling.Abstractions/ConflictError.cs b/src/Winton.DomainModelling.Abstractions/ConflictError.cs
index 18d4458..0d2d54b 100644
--- a/src/Winton.DomainModelling.Abstractions/ConflictError.cs
+++ b/src/Winton.DomainModelling.Abstractions/ConflictError.cs
@@ -1,22 +1,21 @@
// Copyright (c) Winton. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
-namespace Winton.DomainModelling
+namespace Winton.DomainModelling;
+
+///
+///
+/// An error indicating that a conflicting entity exists.
+///
+public class ConflictError : Error
{
- ///
///
- /// An error indicating that a conflicting entity exists.
+ /// Initializes a new instance of the class.
///
- public class ConflictError : Error
+ /// The detail that describes the error.
+ /// A new instance of .
+ public ConflictError(string detail)
+ : base("Conflict", detail)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// The detail that describes the error.
- /// A new instance of .
- public ConflictError(string detail)
- : base("Conflict", detail)
- {
- }
}
-}
+}
\ No newline at end of file
diff --git a/src/Winton.DomainModelling.Abstractions/DomainException.cs b/src/Winton.DomainModelling.Abstractions/DomainException.cs
deleted file mode 100644
index 04312dc..0000000
--- a/src/Winton.DomainModelling.Abstractions/DomainException.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) Winton. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
-
-using System;
-
-namespace Winton.DomainModelling
-{
- ///
- ///
- /// Represents domain errors.
- ///
- [Obsolete("Prefer to return results with an Error instead.", false)]
- public class DomainException : Exception
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The message that describes the error.
- public DomainException(string message)
- : base(message)
- {
- }
- }
-}
\ No newline at end of file
diff --git a/src/Winton.DomainModelling.Abstractions/Entity.cs b/src/Winton.DomainModelling.Abstractions/Entity.cs
index b602e82..4ac0c7c 100644
--- a/src/Winton.DomainModelling.Abstractions/Entity.cs
+++ b/src/Winton.DomainModelling.Abstractions/Entity.cs
@@ -3,101 +3,100 @@
using System;
-namespace Winton.DomainModelling
+namespace Winton.DomainModelling;
+
+///
+///
+/// A base class to implement entity types, which are defined by their identity rather than their attributes.
+///
+/// The ID type for the entity type.
+public abstract class Entity : IEquatable>
+ where TEntityId : IEquatable
{
- ///
///
- /// A base class to implement entity types, which are defined by their identity rather than their attributes.
+ /// Initializes a new instance of the class.
///
- /// The ID type for the entity type.
- public abstract class Entity : IEquatable>
- where TEntityId : IEquatable
+ /// The ID for the entity.
+ protected Entity(TEntityId id)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// The ID for the entity.
- protected Entity(TEntityId id)
- {
- Id = id;
- }
+ Id = id;
+ }
- ///
- /// Gets the ID for the entity.
- ///
- public TEntityId Id { get; }
+ ///
+ /// Gets the ID for the entity.
+ ///
+ public TEntityId Id { get; }
- ///
- /// Indicates whether two entities are equal.
- ///
- /// The first entity.
- /// The second entity.
- /// if the entities have the same ID; otherwise, .
- public static bool operator ==(Entity? left, Entity? right)
- {
- return Equals(left, right);
- }
+ ///
+ /// Indicates whether two entities are equal.
+ ///
+ /// The first entity.
+ /// The second entity.
+ /// if the entities have the same ID; otherwise, .
+ public static bool operator ==(Entity? left, Entity? right)
+ {
+ return Equals(left, right);
+ }
- ///
- /// Indicates whether two entities are unequal.
- ///
- /// The first entity.
- /// The second entity.
- /// if the entities have different IDs; otherwise, .
- public static bool operator !=(Entity? left, Entity? right)
- {
- return !Equals(left, right);
- }
+ ///
+ /// Indicates whether two entities are unequal.
+ ///
+ /// The first entity.
+ /// The second entity.
+ /// if the entities have different IDs; otherwise, .
+ public static bool operator !=(Entity? left, Entity? right)
+ {
+ return !Equals(left, right);
+ }
- ///
- ///
- /// Indicates whether the current entity is equal to another entity.
- ///
- /// An entity to compare with this entity.
- ///
- /// if the current entity has the same ID as the entity;
- /// otherwise, .
- ///
- public bool Equals(Entity? other)
+ ///
+ ///
+ /// Indicates whether the current entity is equal to another entity.
+ ///
+ /// An entity to compare with this entity.
+ ///
+ /// if the current entity has the same ID as the entity;
+ /// otherwise, .
+ ///
+ public bool Equals(Entity? other)
+ {
+ if (other is null)
{
- if (other is null)
- {
- return false;
- }
-
- if (ReferenceEquals(this, other))
- {
- return true;
- }
-
- if (GetType() != other.GetType())
- {
- return false;
- }
-
- return !Id.Equals(default!) && !other.Id.Equals(default!) && Id.Equals(other.Id);
+ return false;
}
- ///
- /// Determines whether the specified object is equal to the current object.
- ///
- /// The object to compare with the current object.
- ///
- /// if the specified object is equal to the current object; otherwise,
- /// .
- ///
- public override bool Equals(object? obj)
+ if (ReferenceEquals(this, other))
{
- return Equals(obj as Entity);
+ return true;
}
- ///
- /// Serves as the default hash function.
- ///
- /// A hash code for the current object.
- public override int GetHashCode()
+ if (GetType() != other.GetType())
{
- return Id.GetHashCode();
+ return false;
}
+
+ return !Id.Equals(default!) && !other.Id.Equals(default!) && Id.Equals(other.Id);
+ }
+
+ ///
+ /// Determines whether the specified object is equal to the current object.
+ ///
+ /// The object to compare with the current object.
+ ///
+ /// if the specified object is equal to the current object; otherwise,
+ /// .
+ ///
+ public override bool Equals(object? obj)
+ {
+ return Equals(obj as Entity);
+ }
+
+ ///
+ /// Serves as the default hash function.
+ ///
+ /// A hash code for the current object.
+ public override int GetHashCode()
+ {
+ return Id.GetHashCode();
}
-}
\ No newline at end of file
+}
diff --git a/src/Winton.DomainModelling.Abstractions/EntityNotFoundException.cs b/src/Winton.DomainModelling.Abstractions/EntityNotFoundException.cs
deleted file mode 100644
index 1bae265..0000000
--- a/src/Winton.DomainModelling.Abstractions/EntityNotFoundException.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) Winton. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
-
-using System;
-
-namespace Winton.DomainModelling
-{
- ///
- ///
- /// An error indicating that an entity could not be found.
- ///
- [Obsolete("Prefer to return results with a NotFoundError instead.", false)]
- public class EntityNotFoundException : DomainException
- {
- private EntityNotFoundException(string message)
- : base(message)
- {
- }
-
- ///
- /// Creates a new instance of the class using the generic constraint to generate
- /// the message.
- ///
- /// The type of the entity.
- /// The type of the entity id.
- /// A new instance of .
- public static EntityNotFoundException Create()
- where TEntity : Entity
- where TEntityId : IEquatable
- {
- return new EntityNotFoundException($"The specified {typeof(TEntity).Name} could not be found.");
- }
- }
-}
\ No newline at end of file
diff --git a/src/Winton.DomainModelling.Abstractions/Error.cs b/src/Winton.DomainModelling.Abstractions/Error.cs
index 1d43d4f..f4502ab 100644
--- a/src/Winton.DomainModelling.Abstractions/Error.cs
+++ b/src/Winton.DomainModelling.Abstractions/Error.cs
@@ -1,43 +1,42 @@
// Copyright (c) Winton. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
-namespace Winton.DomainModelling
+namespace Winton.DomainModelling;
+
+///
+/// The base class of all errors in the domain model.
+///
+///
+/// In a domain model it is better to explicitly model errors rather than throw exceptions.
+/// Errors are legitimate outcomes of operations in a domain model where an operation is
+/// not guaranteed to succeed. Errors can occur for several reasons, such as not being able
+/// to find a requested entity or because the inputs received were invalid.
+/// On the other hand, exceptions should be used in exceptional circumstances that have
+/// occurred due to factors outside of the domain model's control, e.g. network failures.
+/// In general, problems in the domain model should be modelled as errors and exceptions should
+/// be reserved for cases where the user cannot be given information on how to correct the problem.
+///
+public class Error
{
///
- /// The base class of all errors in the domain model.
+ /// Initializes a new instance of the class.
///
- ///
- /// In a domain model it is better to explicitly model errors rather than throw exceptions.
- /// Errors are legitimate outcomes of operations in a domain model where an operation is
- /// not guaranteed to succeed. Errors can occur for several reasons, such as not being able
- /// to find a requested entity or because the inputs received were invalid.
- /// On the other hand, exceptions should be used in exceptional circumstances that have
- /// occurred due to factors outside of the domain model's control, e.g. network failures.
- /// In general, problems in the domain model should be modelled as errors and exceptions should
- /// be reserved for cases where the user cannot be given information on how to correct the problem.
- ///
- public class Error
+ /// The title for this type of error.
+ /// The detail that describes the error.
+ /// A new instance of .
+ public Error(string title, string detail)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// The title for this type of error.
- /// The detail that describes the error.
- /// A new instance of .
- public Error(string title, string detail)
- {
- Title = title;
- Detail = detail;
- }
+ Title = title;
+ Detail = detail;
+ }
- ///
- /// Gets the detail that describes the error.
- ///
- public string Detail { get; }
+ ///
+ /// Gets the detail that describes the error.
+ ///
+ public string Detail { get; }
- ///
- /// Gets the title of the error. This should be the same for all instances of the same error type.
- ///
- public string Title { get; }
- }
-}
\ No newline at end of file
+ ///
+ /// Gets the title of the error. This should be the same for all instances of the same error type.
+ ///
+ public string Title { get; }
+}
diff --git a/src/Winton.DomainModelling.Abstractions/Failure.cs b/src/Winton.DomainModelling.Abstractions/Failure.cs
index cc1f8fa..1559b52 100644
--- a/src/Winton.DomainModelling.Abstractions/Failure.cs
+++ b/src/Winton.DomainModelling.Abstractions/Failure.cs
@@ -4,142 +4,141 @@
using System;
using System.Threading.Tasks;
-namespace Winton.DomainModelling
+namespace Winton.DomainModelling;
+
+///
+///
+/// A result indicating a failure.
+///
+public sealed class Failure : Result
{
- ///
///
- /// A result indicating a failure.
+ /// Initializes a new instance of the class.
+ ///
+ /// The error that caused the result to be a failure.
+ /// A new instance of .
+ public Failure(Error error)
+ {
+ Error = error;
+ }
+
+ ///
+ /// Gets the error that caused the failure.
///
- public sealed class Failure : Result
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The error that caused the result to be a failure.
- /// A new instance of .
- public Failure(Error error)
- {
- Error = error;
- }
-
- ///
- /// Gets the error that caused the failure.
- ///
- public Error Error { get; }
-
- ///
- public override Result Catch(Func> onFailure)
- {
- return onFailure(Error);
- }
-
- ///
- public override Task> Catch(Func>> onFailure)
- {
- return onFailure(Error);
- }
-
- ///
- public override Result Combine(
- Result other,
- Func combineData,
- Func combineErrors)
- {
- return other.Match>(
- otherData => new Failure(Error),
- otherError => new Failure(combineErrors(Error, otherError)));
- }
-
- ///
- public override T Match(Func onSuccess, Func onFailure)
- {
- return onFailure(Error);
- }
-
- ///
- public override Result OnFailure(Action onFailure)
- {
- return OnFailure(_ => onFailure());
- }
-
- ///
- public override Result OnFailure(Action onFailure)
- {
- onFailure(Error);
- return this;
- }
-
- ///
- public override Task> OnFailure(Func onFailure)
- {
- return OnFailure(_ => onFailure());
- }
-
- ///
- public override async Task> OnFailure(Func onFailure)
- {
- await onFailure(Error);
- return this;
- }
-
- ///
- public override Result OnSuccess(Action onSuccess)
- {
- return this;
- }
-
- ///
- public override Result OnSuccess(Action onSuccess)
- {
- return this;
- }
-
- ///
- public override Task> OnSuccess(Func onSuccess)
- {
- return Task.FromResult>(this);
- }
-
- ///
- public override Task> OnSuccess(Func onSuccess)
- {
- return Task.FromResult>(this);
- }
-
- ///
- public override Result Select(Func selector)
- {
- return new Failure(Error);
- }
-
- ///