{"id":19839593,"url":"https://github.com/pedrior/result-extensions","last_synced_at":"2025-02-28T19:17:20.989Z","repository":{"id":231881958,"uuid":"782679042","full_name":"pedrior/result-extensions","owner":"pedrior","description":"A extremely simple library providing a discriminated union type powered with fluent extensions for .NET.","archived":false,"fork":false,"pushed_at":"2024-04-15T15:04:08.000Z","size":54,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-04-30T13:29:21.372Z","etag":null,"topics":["aspnetcore","best-practices","discriminated-unions","dotnet","error","error-handling","extensions","fluentassertions","pattern","result","result-pattern","results"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pedrior.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-05T19:41:23.000Z","updated_at":"2024-05-04T19:20:07.284Z","dependencies_parsed_at":"2024-05-04T16:31:54.976Z","dependency_job_id":"70f1be03-9f41-420a-af2f-a7e8112e5fce","html_url":"https://github.com/pedrior/result-extensions","commit_stats":null,"previous_names":["pedrior/result-extensions"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrior%2Fresult-extensions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrior%2Fresult-extensions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrior%2Fresult-extensions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrior%2Fresult-extensions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pedrior","download_url":"https://codeload.github.com/pedrior/result-extensions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241209545,"owners_count":19927735,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aspnetcore","best-practices","discriminated-unions","dotnet","error","error-handling","extensions","fluentassertions","pattern","result","result-pattern","results"],"created_at":"2024-11-12T12:23:20.892Z","updated_at":"2025-02-28T19:17:20.964Z","avatar_url":"https://github.com/pedrior.png","language":"C#","readme":"[![Build Workflow Status](https://img.shields.io/github/actions/workflow/status/pedrior/result-extensions/build.yml?label=build)](https://github.com/pedrior/result-extensions/actions/workflows/build.yml)\n[![ResultExtensions Nuget Package](https://img.shields.io/nuget/v/ResultExtensions?label=ResultExtensions)](https://www.nuget.org/packages/ResultExtensions)\n[![ResultExtensions.AspNetCore Nuget Package](https://img.shields.io/nuget/v/ResultExtensions.AspNetCore?label=ResultExtensions.AspNetCore)](https://www.nuget.org/packages/ResultExtensions.AspNetCore)\n[![ResultExtensions.FluentAssertions Nuget Package](https://img.shields.io/nuget/v/ResultExtensions.FluentAssertions?label=ResultExtensions.FluentAssertions)](https://www.nuget.org/packages/ResultExtensions.FluentAssertions)\n\n# Result Extensions\n\nA extremely simple library that provides a discriminated union type enhanced with fluent extensions for .NET. This project is completely based on [Amichai Mantinband's ErrorOr](https://github.com/amantinband/error-or).\n\n## Introduction\n\nThe Result pattern is a functional programming approach used to represent the outcome of a computation that can either\nsucceed with a value or fail with one or more errors. This can help make error handling more explicit and prevent\nunexpected runtime errors. This project offers a simple discriminated union type for .NET, powered with fluent \nextension functions and support for ASP.NET Core's `IResult` and `IActionResult` response objects.\n\n### What issue is this project attempting to address?\n\nWhen talking about error handling in .NET, the first thing that comes to mind is exceptions. Exceptions are a powerful\nmechanism for handling errors. When an exception is thrown, the method's execution is interrupted, and the runtime\nsearches for a catch block that can handle the exception. This approach, known as the fast-fail principle, proves\nbeneficial in numerous scenarios. However, exceptions have some drawbacks:\n\n- __Performance__: Throwing and catching exceptions can incur a significant performance cost, as it involves stack\n  unwinding, context switching, and memory allocation. This can be problematic in performance-critical scenarios.\n\n- __Complexity__: Exceptions can disrupt the normal flow of control in your application, making the code harder to read\nand understand. They can lead to non-linear code execution paths, which may complicate debugging and maintenance.\n\n- __Overuse__: Over-reliance on exceptions for control flow or error handling can lead to poorly structured code. This\n  can make it harder to reason about the code and can result in unexpected behavior.\n\n- __Implicit__: Exceptions are not part of a method's signature, meaning that the caller must be aware of the exceptions\n  that a method can throw.\n\n- __Testing__: Testing code that throws exceptions can be challenging, as you need to set up the test environment to\n  trigger or bypass the exception. This can make it harder to write unit tests and verify the behavior of the code.\n\nThe Result pattern is an alternative approach to error handling that addresses these issues. Instead of throwing\nexceptions, a method returns a result object that encapsulates the outcome of the operation. This result object can\nrepresent either a successful result or an error, along with additional information about the error. By making the error\nexplicit, the Result pattern can help improve code performance, readability, maintainability, and testability.\n\nThis doesn't mean we should replace exceptions entirely. Exceptions should be used for exceptional cases, not as a \nregular part of program execution.\n\n## Getting Started\n\nJust add the package to begin using it:\n\n```shell\ndotnet add package ResultExtensions\n```\n\nYou might want to consider adding the ASP.NET Core extensions package as well:\n\n```shell\ndotnet add package ResultExtensions.AspNetCore\n```\n\nIf you are using [FluentAssertions](https://github.com/fluentassertions/fluentassertions) to write tests, we offer a package with specialized assertions:\n\n```shell\ndotnet add package ResultExtensions.FluentAssertions\n```\n\nNow that the necessary packages have been added, let's explore the capabilities of the ResultExtensions.\n\n## Features\n\nLet's explore some of the features provided by the ResultExtensions library.\n\n### Basic usage\n\n#### Returns either a value or an error\n\n```csharp\npublic Result\u003cint\u003e Divide(int dividend, int divisor)\n{\n    if (divisor is 0)\n    {\n        return Error.Failure(\"Cannot divide by zero.\");\n    }\n\n    return dividend / divisor;\n}\n```\n\n#### Returns either a value or multiple errors\n\n```csharp\npublic Result\u003cint\u003e Validate(int value)\n{\n    var errors = new List\u003cError\u003e();\n\n    if (value \u003c 0)\n    {\n        errors.Add(Error.Validation(\"Value must be greater than or equal to zero.\"));\n    }\n\n    if (value % 2 is not 0)\n    {\n        errors.Add(Error.Validation(\"Value must be an even number.\"));\n    }\n\n    return errors.Length is 0 ? value : errors;\n}\n```\n\n### Creating a `Result\u003cT\u003e`\n\n#### From implicit conversions\n\n##### To a successful result\n\n```csharp\nResult\u003cstring\u003e r1 = \"Hello, World!\";\nResult\u003cPoint\u003e r2 = new Point(10, 20);\n```\n\n##### To a failed result\n\n```csharp\nResult\u003cstring\u003e r1 = Error.Validation(\"Must start with a letter.\");\nResult\u003cstring\u003e r2 = new[] \n{ \n    Error.Validation(\"Must start with a letter.\"),\n    Error.Validation(\"Must be at least 8 characters long.\")\n};\n```\n\n#### From static factory methods\n\n##### To a successful result\n\n```csharp\nvar r1 = Result\u003cint\u003e.Success(42);\nvar r2 = Result\u003cPoint\u003e.Success(new Point(10, 20));\n```\n\n##### To a failed result\n\n```csharp\nvar r1 = Result\u003cstring\u003e.Failure(Error.Validation(\"Must start with a letter.\"));\n\nvar r2 = Result\u003cstring\u003e.Failure(\n    Error.Validation(\"Must start with a letter.\"),\n    Error.Validation(\"Must be at least 8 characters long.\"));\n\nvar r3 = Result\u003cstring\u003e.Failure(new[]\n{\n    Error.Validation(\"Must start with a letter.\"),\n    Error.Validation(\"Must be at least 8 characters long.\")\n});\n\nvar r4 = Result\u003cstring\u003e.Failure(new List\u003cError\u003e\n{\n    Error.Validation(\"Must start with a letter.\"),\n    Error.Validation(\"Must be at least 8 characters long.\")\n});\n\nvar r5 = Result\u003cstring\u003e.Failure(ImmutableArray.Create(\n    Error.Validation(\"Must start with a letter.\"),\n    Error.Validation(\"Must be at least 8 characters long.\")));\n```\n\n### Handling the result\n\n#### Using the `Switch` method\n\nThe `Switch` method allows you to specify separate actions for the success and failure cases.\n\n```csharp\nResult\u003cint\u003e Process(int x)\n{ ... }\n\nProcess(5).Switch(\n    onSuccess: value =\u003e Console.WriteLine($\"Success: {value}\"),\n    onFailure: error =\u003e Console.WriteLine($\"Failure: {error}\"));\n```\n\n#### Using the `Match` method\n\nThe `Match` method allows you to specify separate actions for the success and failure cases and return a new value.\n\n```csharp\nResult\u003cint\u003e Process(int x)\n{ ... }\n\nvar str = Process(5).Match\u003cstring\u003e(\n    onSuccess: value =\u003e value.ToString(),\n    onFailure: error =\u003e error.Message);\n```\n\n\u003e Both `Switch` and `Match` methods have a `*All` variant that allows you to capture all errors in the failure case.\n\n:construction: Work in progress...\n\n## Documentation\n\nAll public types and members are documented. The documentation can be found in the source code.\n\n## Inspired By\n\n- [amantinband/error-or](https://github.com/amantinband/error-or)\n- [ardalis/Result](https://github.com/ardalis/Result)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpedrior%2Fresult-extensions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpedrior%2Fresult-extensions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpedrior%2Fresult-extensions/lists"}