From 218293a37230c9261a8d6fef9db297ae234b03d8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 01:28:40 +0000 Subject: [PATCH 1/5] Initial plan From a1ae21ac6c7bba65e9edf575de33bda156f10581 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 01:39:06 +0000 Subject: [PATCH 2/5] Create getting-started.md, introduction.md, readme.md, setup.md files Co-authored-by: Chris-Wolfgang <210299580+Chris-Wolfgang@users.noreply.github.com> --- getting-started.md | 206 +++++++++++++++++++++++++++++++++++++++++++++ introduction.md | 77 +++++++++++++++++ readme.md | 162 +++++++++++++++++++++++++++++++++++ setup.md | 200 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 645 insertions(+) create mode 100644 getting-started.md create mode 100644 introduction.md create mode 100644 readme.md create mode 100644 setup.md diff --git a/getting-started.md b/getting-started.md new file mode 100644 index 0000000..c4ccd56 --- /dev/null +++ b/getting-started.md @@ -0,0 +1,206 @@ +# Getting Started + +This guide will help you get up and running with the Try Pattern library in just a few minutes. + +## Installation + +### NuGet Package + +Install the Try Pattern library via NuGet Package Manager: + +```bash +dotnet add package Wolfgang.TryPattern +``` + +Or using the Package Manager Console: + +```powershell +Install-Package Wolfgang.TryPattern +``` + +### Manual Installation + +Alternatively, you can clone the repository and reference the project directly: + +```bash +git clone https://github.com/Chris-Wolfgang/Try-Pattern.git +``` + +## Basic Usage + +### 1. Using Try with Async Operations + +The most common use case is wrapping async operations that may fail: + +```csharp +using Wolfgang.TryPattern; + +// Reading a file that might not exist +var result = await Try.RunAsync(() => File.ReadAllTextAsync("data.txt")); + +if (result.Succeeded) +{ + Console.WriteLine($"File content: {result.Value}"); +} +else +{ + Console.WriteLine($"Failed to read file: {result.ErrorMessage}"); +} +``` + +### 2. Using Try with Synchronous Operations + +You can also use the Try Pattern with synchronous operations: + +```csharp +using Wolfgang.TryPattern; + +// Parsing a JSON file +var result = Try.Run(() => JsonSerializer.Deserialize(jsonString)); + +if (result.Succeeded) +{ + ProcessData(result.Value); +} +else +{ + LogError(result.ErrorMessage); +} +``` + +### 3. Using Result for Custom Methods + +Use `Result` and `Result` as return types for your own methods: + +```csharp +using Wolfgang.TryPattern; + +public Result ValidateEmail(string email) +{ + if (string.IsNullOrWhiteSpace(email)) + { + return Result.Failure("Email cannot be empty"); + } + + if (!email.Contains("@")) + { + return Result.Failure("Email must contain @"); + } + + return Result.Success(); +} + +public Result GetUser(int userId) +{ + var user = database.FindUser(userId); + + if (user == null) + { + return Result.Failure("User not found"); + } + + return Result.Success(user); +} +``` + +## Common Patterns + +### Pattern 1: File Operations + +```csharp +var result = await Try.RunAsync(() => File.ReadAllTextAsync(filePath)); +if (!result.Succeeded) +{ + // Handle failure - file doesn't exist, no permissions, etc. + return; +} + +// Process the file content +var content = result.Value; +``` + +### Pattern 2: HTTP Requests + +```csharp +public async Task> FetchDataAsync(string url) +{ + using var response = await httpClient.GetAsync(url); + + if (!response.IsSuccessStatusCode) + { + return Result.Failure($"HTTP {response.StatusCode}"); + } + + var content = await response.Content.ReadAsStringAsync(); + return Result.Success(content); +} +``` + +### Pattern 3: Database Operations + +```csharp +public async Task SaveUserAsync(User user) +{ + if (user == null) + { + throw new ArgumentNullException(nameof(user)); // Programming error + } + + var saveResult = await Try.RunAsync(() => database.SaveAsync(user)); + + if (!saveResult.Succeeded) + { + return Result.Failure("Failed to save user to database"); + } + + return Result.Success(); +} +``` + +## Examples + +The repository includes several example projects demonstrating the Try Pattern in different scenarios: + +- **C# .NET 8 Example**: Modern C# with latest features +- **C# .NET 4.6.2 Example**: Legacy framework support +- **F# Examples**: Functional programming approach +- **VB.NET Examples**: Visual Basic support + +You can find these examples in the `examples` folder of the repository. + +## API Reference + +### Try Class + +- `Try.Run(Func func)`: Execute a synchronous function +- `Try.RunAsync(Func> func)`: Execute an async function +- `Try.Run(Action action)`: Execute a synchronous action +- `Try.RunAsync(Func func)`: Execute an async action + +### Result Class + +- `Result.Success()`: Create a successful result +- `Result.Failure(string message)`: Create a failed result +- `Succeeded`: Boolean indicating success +- `ErrorMessage`: Error message when failed + +### Result Class + +- `Result.Success(T value)`: Create a successful result with a value +- `Result.Failure(string message)`: Create a failed result +- `Succeeded`: Boolean indicating success +- `Value`: The returned value when successful +- `ErrorMessage`: Error message when failed + +## Next Steps + +- Read the [Introduction](introduction.md) for a deeper understanding of the Try Pattern +- Check out the examples in the `examples` folder +- Review the [README.md](README.md) for more detailed examples +- Explore the source code in the `src/Wolfgang.TryPattern` folder + +## Need Help? + +- Open an issue on [GitHub](https://github.com/Chris-Wolfgang/Try-Pattern/issues) +- Check the [Contributing Guide](CONTRIBUTING.md) if you want to contribute +- Review the [Code of Conduct](CODE_OF_CONDUCT.md) diff --git a/introduction.md b/introduction.md new file mode 100644 index 0000000..adb32e6 --- /dev/null +++ b/introduction.md @@ -0,0 +1,77 @@ +# Introduction + +Welcome to the Try Pattern library! This library provides a simple and effective way to implement the Try Pattern in your C# applications. + +## What is the Try Pattern? + +The Try Pattern is a design pattern where code execution returns success/failure status without exposing detailed exception information to the caller. This is particularly useful when: + +- The caller only needs to know if an operation succeeded or failed +- The specific reason for failure is not relevant to the caller +- You want to avoid using exceptions for control flow + +## Why Use the Try Pattern? + +### Benefits + +1. **Simplified Error Handling**: No need to catch and handle specific exceptions +2. **Cleaner Code**: Reduces try-catch blocks throughout your codebase +3. **Better Performance**: Avoids the overhead of exception creation for expected failures +4. **Clearer Intent**: Makes it explicit that an operation may fail + +### Real-World Examples + +You're already familiar with the Try Pattern from .NET's built-in types: +- `int.TryParse(string, out int)` +- `DateTime.TryParse(string, out DateTime)` +- `Dictionary.TryGetValue(TKey, out TValue)` + +## How This Library Helps + +This library extends the Try Pattern to any operation by providing: + +1. **`Try` Class**: Static helper methods to execute operations and handle exceptions +2. **`Result` Type**: Represents the outcome of an operation without a return value +3. **`Result` Type**: Represents the outcome of an operation that returns a value + +## Quick Example + +```csharp +// Without Try Pattern - traditional approach +try +{ + var content = await File.ReadAllTextAsync("config.json"); + ProcessConfig(content); +} +catch (Exception ex) +{ + Console.WriteLine("Error reading config: " + ex.Message); +} + +// With Try Pattern - simplified approach +var result = await Try.RunAsync(() => File.ReadAllTextAsync("config.json")); +if (result.Succeeded) +{ + ProcessConfig(result.Value); +} +else +{ + Console.WriteLine("Error reading config: " + result.ErrorMessage); +} +``` + +## When to Use the Try Pattern + +**Use the Try Pattern when:** +- Operations may fail in expected ways (file not found, network timeout, etc.) +- The caller only needs success/failure information +- You want to avoid exception-based control flow + +**Don't use the Try Pattern when:** +- You need specific exception details for different error handling +- The failure is truly exceptional and should propagate up the call stack +- You're dealing with programming errors (null arguments, invalid state) + +## Next Steps + +Ready to get started? Check out the [Getting Started](getting-started.md) guide to learn how to install and use the library in your projects. diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..4ba4876 --- /dev/null +++ b/readme.md @@ -0,0 +1,162 @@ +# Try Pattern + +## Definition + +The `Try Pattern` is a design pattern in which code is execute but the caller only cares if the code +succeeded or failed and the exact reason for failure is not important. For example, a user may need +to update a record in a database via a web page. If the update fails, they only need to know that it +failed, not the specific reason for the failure. Connection timeout, login failed, user doesn't have +access, etc., are irrelevant to the user. They just need to know if the update succeeded or failed. + +A variation of this, is calling a method that returns a value (i.e. a function). In this case if the +call succeeds, the caller wants the return value from the method. However, if the call fails, the +caller does not care about the specific reason for the failure. This can be seen in many of the +built-in types in C#, such as `int.TryParse` or `DateTime.TryParse`. In these methods, if the operation +succeeds, it returns true and the parsed value is returned via an out parameter. If the method fails +it returns false and the default value is returned via the output parameter. + + +## Library Description + +This library makes it easy to implement the Try Pattern in your own code. It has a +`static` `class` called [`Try`](src/Wolfgang.TryPattern/Try.cs) that provides a set +of `static` helper methods that implement the Try Pattern for both +actions (methods that do not return a value) and functions (methods that return a value). +These helper methods, execute the [`Action`](https://learn.microsoft.com/en-us/dotnet/api/system.action-1?view=net-10.0) +or [`Func`](https://learn.microsoft.com/en-us/dotnet/api/system.func-1?view=net-10.0) +passed in, handle any exceptions, and returns a [`Result`](src/Wolfgang.TryPattern/Result.cs) +for actions, or [`Result`](src/Wolfgang.TryPattern/Result.cs) for functions. + +## Usage +```csharp + + // Try reading a file async + var result = await Try.RunAsync(() => File.ReadAllTextAsync(@".\sample.txt")); + + // If file read failed, print the error message + if (result.Succeeded) + { + Console.WriteLine("File contents:"); + Console.WriteLine(result.Value); + } + else + { + Console.WriteLine("Error reading file: " + result.ErrorMessage); + } +``` + +## Other Uses for `Result` and `Result` + +The `Result` and `Result` types can be used outside of the Try Pattern +The classes work well as return types for methods that need to indicate success or failure +For example consider the following example of a method that validates user input: +```csharp +public Result ValidateUserInput(string input) +{ + if (string.IsNullOrWhiteSpace(input)) + { + return Result.Failure("Input cannot be empty."); + } + if (input.Length < 5) + { + return Result.Failure("Input must be at least 5 characters long."); + } + return Result.Success(); +} +``` + +A more complex example is a method that processes an order: +```csharp + +public class OrderProcessingService +{ + + private readonly HttpClient httpClient; + private readonly string endpoint; + + public OrderProcessingService(HttpClient httpClient, string endpoint) + { + if (httpClient == null) + { + throw new ArgumentNullException(nameof(httpClient)); + } + if (endpoint == null) + { + throw new ArgumentNullException(nameof(endpoint)); + } + this.httpClient = httpClient; + this.endpoint = endpoint; + } + + public async Task CreateOrderAsync(Order order) + { + + if (order == null) + { + // Throwing exception here because this is a programming error + throw new ArgumentNullException(nameof(order)); + } + + var payload = JsonSerializer.Serialize(order); + using var content = new StringContent(payload, Encoding.UTF8, "application/json"); + using var response = await httpClient.PostAsync(endpoint, content).ConfigureAwait(false); + + + if ((int)response.StatusCode >= 400 && (int)response.StatusCode < 500) + { + var reason = string.IsNullOrWhiteSpace(response.ReasonPhrase) ? "Client Error" : response.ReasonPhrase; + return Result.Failure($"Failed to create order: {(int)response.StatusCode} ({reason})."); + } + else if ((int)response.StatusCode >= 500 && (int)response.StatusCode < 600) + { + var reason = string.IsNullOrWhiteSpace(response.ReasonPhrase) ? "Server Error" : response.ReasonPhrase; + return Result.Failure($"Failed to create order: {(int)response.StatusCode} ({reason})."); + } + + // Fallback for unexpected status codes (e.g., informational or redirection responses) + return Result.Failure($"Failed to create order: {(int)response.StatusCode} ({response.StatusCode})."); + } + + + public async Task> GetOrderAsync(string orderId) + { + + if (string.IsNullOrWhiteSpace(orderId)) + { + // Throwing exception here because this is a programming error + throw new ArgumentNullException(nameof(orderId)); + } + using var response = await httpClient.GetAsync($"{endpoint}/{orderId}").ConfigureAwait(false); + if (response.IsSuccessStatusCode) + { + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var confirmation = JsonSerializer.Deserialize(content); + return Result.Success(confirmation); + } + return Result.Failure($"Failed to get order confirmation. Status code: {response.StatusCode}"); + } +} +``` + + + + +## A Note on Using Exceptions for Control Flow + +Exceptions are generally intended for exceptional circumstances and not for regular control flow. +They are expensive to create and handle, and using them for control flow can lead to code that is harder to follow and understand + +If you have a function that searches for a specific value, it is better to return some value that indicates not found +such as `null`, `false`, or an empty collection, in the case where more than one result could be returned, rather than throwing an exception when the value is not found. + +When creating code that uses the Try Pattern, consider whether exceptions are the best way to indicate failure. +In the case where a user searches for specific data, it is very common that the value +they are searching for does not exist. As such, don't throw an exception when this happens but rather return a value that indicates not found. + +However, failing to connect to a database or a webservice are both +situations where exceptions are appropriate as these are not common occurrences and indicate something unexpected happened. + +Reading a config file or some required other application file that should always be present +is another good example of when to use exceptions for control flow. However, +a application that reads from a user specified file can expect that the file may not exist +and so in that case throwing an exception is probably not the best approach. diff --git a/setup.md b/setup.md new file mode 100644 index 0000000..bd1b958 --- /dev/null +++ b/setup.md @@ -0,0 +1,200 @@ +# Setup Guide + +This guide provides instructions for setting up the Try Pattern library for development and usage. + +## For Library Users + +### Prerequisites + +- .NET 8.0 SDK or later (for .NET 8 projects) +- .NET Framework 4.6.2 or later (for .NET Framework projects) +- Visual Studio 2022, VS Code, or Rider (recommended) + +### Quick Setup + +1. **Install via NuGet** + ```bash + dotnet add package Wolfgang.TryPattern + ``` + +2. **Add using statement** + ```csharp + using Wolfgang.TryPattern; + ``` + +3. **Start using the library** + ```csharp + var result = await Try.RunAsync(() => SomeOperationAsync()); + ``` + +## For Contributors + +### Prerequisites + +- .NET 8.0 SDK +- Git +- Visual Studio 2022, VS Code, or Rider + +### Clone the Repository + +```bash +git clone https://github.com/Chris-Wolfgang/Try-Pattern.git +cd Try-Pattern +``` + +### Build the Solution + +```bash +dotnet restore +dotnet build +``` + +### Run Tests + +```bash +dotnet test +``` + +### Project Structure + +``` +Try-Pattern/ +├── src/ +│ └── Wolfgang.TryPattern/ # Main library project +├── tests/ +│ └── Wolfgang.TryPattern.Tests/ # Unit tests +├── examples/ +│ ├── CSharp.DotNet8.Example/ # C# .NET 8 examples +│ ├── CSharp.DotNet462.Example/ # C# .NET Framework examples +│ ├── FSharp.DotNet8.Example/ # F# .NET 8 examples +│ ├── FSharp.DotNet462.Example/ # F# .NET Framework examples +│ ├── VB.DotNet8.Example/ # VB.NET .NET 8 examples +│ └── VB.DotNet462.Example/ # VB.NET .NET Framework examples +├── benchmarks/ # Performance benchmarks +└── docs/ # Documentation files +``` + +## Development Workflow + +### 1. Create a Feature Branch + +```bash +git checkout -b feature/your-feature-name +``` + +### 2. Make Changes + +Edit the code, add tests, and ensure all tests pass. + +### 3. Run Quality Checks + +```bash +# Run tests +dotnet test + +# Build the solution +dotnet build + +# Run benchmarks (optional) +cd benchmarks +dotnet run -c Release +``` + +### 4. Commit and Push + +```bash +git add . +git commit -m "Add: your feature description" +git push origin feature/your-feature-name +``` + +### 5. Create Pull Request + +Open a pull request on GitHub and wait for review. + +## Building Documentation + +The project uses DocFX for documentation generation. + +```bash +cd docfx_project +docfx build +docfx serve +``` + +Visit `http://localhost:8080` to view the documentation. + +## Running Examples + +Navigate to any example project and run: + +```bash +cd examples/CSharp.DotNet8.Example +dotnet run +``` + +## Troubleshooting + +### Build Errors + +**Issue**: Missing .NET SDK version +``` +Solution: Install the required .NET SDK from https://dotnet.microsoft.com/download +``` + +**Issue**: NuGet package restore fails +``` +Solution: Clear NuGet cache and restore +dotnet nuget locals all --clear +dotnet restore +``` + +### Test Failures + +**Issue**: Tests fail on first run +``` +Solution: Ensure all dependencies are restored +dotnet restore +dotnet build +dotnet test +``` + +## IDE Setup + +### Visual Studio 2022 + +1. Open `TryPattern.sln` +2. Restore NuGet packages (automatic) +3. Build solution (Ctrl+Shift+B) +4. Run tests (Ctrl+R, A) + +### VS Code + +1. Open folder in VS Code +2. Install C# extension +3. Use integrated terminal for commands: + ```bash + dotnet build + dotnet test + ``` + +### Rider + +1. Open `TryPattern.sln` +2. Restore NuGet packages (automatic) +3. Build solution +4. Run tests from Test Explorer + +## Contributing + +Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## Support + +- **Issues**: Report bugs or request features on [GitHub Issues](https://github.com/Chris-Wolfgang/Try-Pattern/issues) +- **Discussions**: Ask questions in [GitHub Discussions](https://github.com/Chris-Wolfgang/Try-Pattern/discussions) +- **Documentation**: Check the [docs](docs/) folder for detailed documentation From 07c976e118e4c415c1f088f4736b7fad7634899f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 01:40:35 +0000 Subject: [PATCH 3/5] Fix grammar, code examples, and link references in documentation Co-authored-by: Chris-Wolfgang <210299580+Chris-Wolfgang@users.noreply.github.com> --- getting-started.md | 2 +- readme.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/getting-started.md b/getting-started.md index c4ccd56..1c5d2dc 100644 --- a/getting-started.md +++ b/getting-started.md @@ -196,7 +196,7 @@ You can find these examples in the `examples` folder of the repository. - Read the [Introduction](introduction.md) for a deeper understanding of the Try Pattern - Check out the examples in the `examples` folder -- Review the [README.md](README.md) for more detailed examples +- Review the [readme.md](readme.md) for more detailed examples - Explore the source code in the `src/Wolfgang.TryPattern` folder ## Need Help? diff --git a/readme.md b/readme.md index 4ba4876..6a098e1 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ ## Definition -The `Try Pattern` is a design pattern in which code is execute but the caller only cares if the code +The `Try Pattern` is a design pattern in which code is executed but the caller only cares if the code succeeded or failed and the exact reason for failure is not important. For example, a user may need to update a record in a database via a web page. If the update fails, they only need to know that it failed, not the specific reason for the failure. Connection timeout, login failed, user doesn't have @@ -113,12 +113,12 @@ public class OrderProcessingService return Result.Failure($"Failed to create order: {(int)response.StatusCode} ({reason})."); } - // Fallback for unexpected status codes (e.g., informational or redirection responses) - return Result.Failure($"Failed to create order: {(int)response.StatusCode} ({response.StatusCode})."); + // Success case for 2xx status codes + return Result.Success(); } - public async Task> GetOrderAsync(string orderId) + public async Task> GetOrderAsync(string orderId) { if (string.IsNullOrWhiteSpace(orderId)) @@ -158,5 +158,5 @@ situations where exceptions are appropriate as these are not common occurrences Reading a config file or some required other application file that should always be present is another good example of when to use exceptions for control flow. However, -a application that reads from a user specified file can expect that the file may not exist +an application that reads from a user specified file can expect that the file may not exist and so in that case throwing an exception is probably not the best approach. From 5830730b70bb5af02200b2531191626d514c4ed4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 03:55:05 +0000 Subject: [PATCH 4/5] Update documentation to reflect .NET 4.6.2 through .NET 10 support Co-authored-by: Chris-Wolfgang <210299580+Chris-Wolfgang@users.noreply.github.com> --- getting-started.md | 8 +++++--- setup.md | 5 ++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/getting-started.md b/getting-started.md index 1c5d2dc..57d51c9 100644 --- a/getting-started.md +++ b/getting-started.md @@ -162,9 +162,11 @@ public async Task SaveUserAsync(User user) The repository includes several example projects demonstrating the Try Pattern in different scenarios: - **C# .NET 8 Example**: Modern C# with latest features -- **C# .NET 4.6.2 Example**: Legacy framework support -- **F# Examples**: Functional programming approach -- **VB.NET Examples**: Visual Basic support +- **C# .NET 4.6.2 Example**: .NET Framework support +- **F# Examples**: Functional programming approach (.NET 4.6.2 and .NET 8) +- **VB.NET Examples**: Visual Basic support (.NET 4.6.2 and .NET 8) + +The library itself supports .NET Framework 4.6.2, .NET Standard 2.0, .NET 8.0, and .NET 10.0. You can find these examples in the `examples` folder of the repository. diff --git a/setup.md b/setup.md index bd1b958..acad7bc 100644 --- a/setup.md +++ b/setup.md @@ -6,8 +6,7 @@ This guide provides instructions for setting up the Try Pattern library for deve ### Prerequisites -- .NET 8.0 SDK or later (for .NET 8 projects) -- .NET Framework 4.6.2 or later (for .NET Framework projects) +- .NET SDK (the library supports .NET Framework 4.6.2, .NET Standard 2.0, .NET 8.0, and .NET 10.0) - Visual Studio 2022, VS Code, or Rider (recommended) ### Quick Setup @@ -31,7 +30,7 @@ This guide provides instructions for setting up the Try Pattern library for deve ### Prerequisites -- .NET 8.0 SDK +- .NET 8.0 SDK or later (for building the library which targets .NET 4.6.2 through .NET 10.0) - Git - Visual Studio 2022, VS Code, or Rider From 3ad30073d77bad761b35a5031773b448ac95c1cd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 03:58:33 +0000 Subject: [PATCH 5/5] Add compatibility sections to readme.md and introduction.md Co-authored-by: Chris-Wolfgang <210299580+Chris-Wolfgang@users.noreply.github.com> --- introduction.md | 8 ++++++++ readme.md | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/introduction.md b/introduction.md index adb32e6..9e6c7f7 100644 --- a/introduction.md +++ b/introduction.md @@ -34,6 +34,14 @@ This library extends the Try Pattern to any operation by providing: 2. **`Result` Type**: Represents the outcome of an operation without a return value 3. **`Result` Type**: Represents the outcome of an operation that returns a value +### Compatibility + +The library supports .NET Framework 4.6.2 through .NET 10.0, including: +- .NET Framework 4.6.2 and later +- .NET Standard 2.0 +- .NET 8.0 +- .NET 10.0 + ## Quick Example ```csharp diff --git a/readme.md b/readme.md index 6a098e1..915a833 100644 --- a/readme.md +++ b/readme.md @@ -27,6 +27,14 @@ or [`Func`](https://learn.microsoft.com/en-us/dotnet/api/system.func-1?view=n passed in, handle any exceptions, and returns a [`Result`](src/Wolfgang.TryPattern/Result.cs) for actions, or [`Result`](src/Wolfgang.TryPattern/Result.cs) for functions. +## Compatibility + +This library supports the following .NET platforms: +- .NET Framework 4.6.2 and later +- .NET Standard 2.0 +- .NET 8.0 +- .NET 10.0 + ## Usage ```csharp