{"id":13430498,"url":"https://github.com/vkhorikov/CSharpFunctionalExtensions","last_synced_at":"2025-03-16T05:31:16.054Z","repository":{"id":37431849,"uuid":"61425212","full_name":"vkhorikov/CSharpFunctionalExtensions","owner":"vkhorikov","description":"Functional extensions for C#","archived":false,"fork":false,"pushed_at":"2025-02-22T12:24:59.000Z","size":1734,"stargazers_count":2561,"open_issues_count":98,"forks_count":312,"subscribers_count":81,"default_branch":"master","last_synced_at":"2025-03-13T02:04:01.589Z","etag":null,"topics":["csharp","entity","functional-programming","maybe-monad","result","value-object"],"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/vkhorikov.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":"2016-06-18T08:50:27.000Z","updated_at":"2025-03-10T23:17:28.000Z","dependencies_parsed_at":"2023-02-12T04:45:40.665Z","dependency_job_id":"e9760164-ae9e-4911-8d52-3035ae00d921","html_url":"https://github.com/vkhorikov/CSharpFunctionalExtensions","commit_stats":null,"previous_names":[],"tags_count":116,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vkhorikov%2FCSharpFunctionalExtensions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vkhorikov%2FCSharpFunctionalExtensions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vkhorikov%2FCSharpFunctionalExtensions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vkhorikov%2FCSharpFunctionalExtensions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vkhorikov","download_url":"https://codeload.github.com/vkhorikov/CSharpFunctionalExtensions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243830912,"owners_count":20354848,"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":["csharp","entity","functional-programming","maybe-monad","result","value-object"],"created_at":"2024-07-31T02:00:54.610Z","updated_at":"2025-03-16T05:31:16.045Z","avatar_url":"https://github.com/vkhorikov.png","language":"C#","readme":"﻿# Functional Extensions for C\u0026#35;\n\n[![Build Status](https://dev.azure.com/EnterpriseCraftsmanship/CSharpFunctionalExtensions/_apis/build/status/CSharpFunctionalExtensions?branchName=master)](https://dev.azure.com/EnterpriseCraftsmanship/CSharpFunctionalExtensions/_build/latest?definitionId=1\u0026branchName=master)\n[![NuGet downloads](https://img.shields.io/nuget/v/csharpfunctionalextensions.svg)](https://www.nuget.org/packages/CSharpFunctionalExtensions/)\n[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/vkhorikov/CSharpFunctionalExtensions/blob/master/LICENSE)\n\nThis library helps write code in more functional way.\nTo get to know more about the principles behind it, check out the [Applying Functional Principles in C# Pluralsight course](https://enterprisecraftsmanship.com/ps-func).\n\n## Installation\n\nAvailable on [NuGet](https://www.nuget.org/packages/CSharpFunctionalExtensions/)\n\n```bash\ndotnet add package CSharpFunctionalExtensions\n```\n\nor\n\n```powershell\nPM\u003e Install-Package CSharpFunctionalExtensions\n```\n\nAlso available as a strong named assembly (big thanks to [bothzoli](https://github.com/bothzoli) who made it possible!).\n\nOn [NuGet](https://www.nuget.org/packages/CSharpFunctionalExtensions.StrongName/)\n\n\n```bash\ndotnet add package CSharpFunctionalExtensions.StrongName\n```\n\n## Core Concepts\n\n### Get rid of primitive obsession\n\n```csharp\nResult\u003cCustomerName\u003e name = CustomerName.Create(model.Name);\nResult\u003cEmail\u003e email = Email.Create(model.PrimaryEmail);\n\nResult result = Result.Combine(name, email);\nif (result.IsFailure)\n    return Error(result.Error);\n\nvar customer = new Customer(name.Value, email.Value);\n```\n\n## Make nulls explicit with the Maybe type\n\n```csharp\nMaybe\u003cCustomer\u003e customerOrNothing = _customerRepository.GetById(id);\nif (customerOrNothing.HasNoValue)\n    return Error(\"Customer with such Id is not found: \" + id);\n```\n\n## Compose multiple operations in a single chain\n\n```csharp\nreturn _customerRepository.GetById(id)\n    .ToResult(\"Customer with such Id is not found: \" + id)\n    .Ensure(customer =\u003e customer.CanBePromoted(), \"The customer has the highest status possible\")\n    .Tap(customer =\u003e customer.Promote())\n    .Tap(customer =\u003e _emailGateway.SendPromotionNotification(customer.PrimaryEmail, customer.Status))\n    .Finally(result =\u003e result.IsSuccess ? Ok() : Error(result.Error));\n```\n\n## Wrap multiple operations in a TransactionScope\n\n```csharp\nreturn _customerRepository.GetById(id)\n    .ToResult(\"Customer with such Id is not found: \" + id)\n    .Ensure(customer =\u003e customer.CanBePromoted(), \"The customer has the highest status possible\")\n    .WithTransactionScope(customer =\u003e Result.Success(customer)\n        .Tap(customer =\u003e customer.Promote())\n        .Tap(customer =\u003e customer.ClearAppointments()))\n    .Tap(customer =\u003e _emailGateway.SendPromotionNotification(customer.PrimaryEmail, customer.Status))\n    .Finally(result =\u003e result.IsSuccess ? Ok() : Error(result.Error));\n```\n\n## API Examples\n\n### Maybe\n\n#### Explicit Construction\n\nUse case: Creating a new Maybe containing a value\n\n```csharp\nMaybe\u003cstring\u003e apple = Maybe\u003cstring\u003e.From(\"apple\");\n\n// or\n\nMaybe\u003cstring\u003e apple = Maybe.From(\"apple\"); // type inference\n\n// or\n\nvar apple = Maybe.From(\"apple\");\n```\n\n#### None/No Value\n\nUse case: Replacing `null` or the\n[Null Object Pattern](https://enterprisecraftsmanship.com/2015/03/13/functional-c-non-nullable-reference-types/) for representing 'missing' data.\n\n```csharp\nint storeInventory = ...\n\nMaybe\u003cstring\u003e fruit = storeInventory \u003e 0\n    ? Maybe\u003cstring\u003e.From(\"apple\")\n    : Maybe\u003cstring\u003e.None;\n\n// or where the generic type is a reference type\n\nMaybe\u003cstring\u003e fruit = null;\n\n// or where the generic type is a value type\n\nMaybe\u003cint\u003e fruit = default;\n```\n\n#### Implicit Conversion\n\nUse case: Easily creating a Maybe from a value\n\n```csharp\n// Constructing a Maybe\nMaybe\u003cstring\u003e apple = \"apple\"; // implicit conversion\n\n// Or as a method return value\nMaybe\u003cstring\u003e GetFruit(string fruit)\n{\n    if (string.IsNullOrWhiteSpace(fruit))\n    {\n        return Maybe\u003cstring\u003e.None;\n    }\n\n    return fruit; // implicit conversion\n}\n```\n\n#### Equality\n\nUse case: Comparing Maybes or values without knowledge of the\ninner value of the Maybes\n\n```csharp\nMaybe\u003cstring\u003e apple = \"apple\";\nMaybe\u003cstring\u003e orange = \"orange\";\nstring alsoOrange = \"orange\";\nMaybe\u003cstring\u003e noFruit = Maybe\u003cstring\u003e.None;\n\nConsole.WriteLine(apple == orange); // false\nConsole.WriteLine(apple != orange); // true\nConsole.WriteLine(orange == alsoOrange); // true\nConsole.WriteLine(alsoOrange == noFruit); // false\n```\n\n#### ToString\n\n```csharp\nMaybe\u003cstring\u003e apple = \"apple\";\nMaybe\u003cstring\u003e noFruit = Maybe\u003cstring\u003e.None;\n\nConsole.WriteLine(apple.ToString()); // \"apple\"\nConsole.WriteLine(noFruit.ToString()); // \"No value\"\n```\n\n#### GetValueOrThrow\n\nUse case: Procedurally accessing the inner value of the Maybe\n\n**Note**: Calling this will throw a `InvalidOperationException` if there is no value\n\n```csharp\nMaybe\u003cstring\u003e apple = \"apple\";\nMaybe\u003cstring\u003e noFruit = Maybe\u003cstring\u003e.None;\n\nConsole.WriteLine(apple.GetValueOrThrow()); // \"apple\";\nConsole.WriteLine(noFruit.GetValueOrThrow()); // throws InvalidOperationException !!\nConsole.WriteLine(noFruit.GetValueOrThrow(new CustomException())); // throws CustomException !!\n```\n\n#### HasValue and HasNoValue\n\nUse case: Procedurally checking if the Maybe has a value,\nusually before accessing the value directly\n\n```csharp\nvoid Response(string fruit)\n{\n    Console.WriteLine($\"Yum, a {fruit} 😀\");\n}\n\nMaybe\u003cstring\u003e apple = \"apple\";\nMaybe\u003cstring\u003e noFruit = Maybe\u003cstring\u003e.None;\n\nif (apple.HasValue)\n{\n    Response(apple.Value); // safe to access since we checked above\n}\n\nif (noFruit.HasNoValue)\n{\n    Response(\"We're all out of fruit 😢\");\n}\n```\n\n#### GetValueOrDefault\n\nUse case: Safely accessing the inner value, without checking if there is one, by providing a fallback\nif no value exists\n\n```csharp\nvoid Response(string fruit)\n{\n    Console.WriteLine($\"It's a {fruit}\");\n}\n\nMaybe\u003cstring\u003e apple = \"apple\";\nMaybe\u003cstring\u003e unknownFruit = Maybe\u003cstring\u003e.None;\n\nstring appleValue = apple.GetValueOrDefault(\"banana\");\nstring unknownFruitValue = unknownFruit.GetValueOrDefault(\"banana\");\n\nResponse(appleValue); // It's a apple\nResponse(unknownFruitValue); // It's a banana\n```\n\n#### Where\n\nUse case: Converting a Maybe with a value to a `Maybe.None` if a condition isn't met\n\n**Note**: The predicate passed to `Where` (ex )\n\n```csharp\nbool IsMyFavorite(string fruit)\n{\n    return fruit == \"papaya\";\n}\n\nMaybe\u003cstring\u003e apple = \"apple\";\n\nMaybe\u003cstring\u003e favoriteFruit = apple.Where(IsMyFavorite);\n\nConsole.WriteLine(favoriteFruit.ToString()); // \"No value\"\n```\n\n#### Map\n\nUse case: Transforming the value in the Maybe, if there is one, without\nneeding to check if the value is there\n\n**Note**: the delegate (ex `CreateMessage`) passed to `Maybe.Map()` is only executed if the Maybe has an inner value\n\n```csharp\nstring CreateMessage(string fruit)\n{\n    return $\"The fruit is a {fruit}\";\n}\n\nMaybe\u003cstring\u003e apple = \"apple\";\nMaybe\u003cstring\u003e noFruit = Maybe\u003cstring\u003e.None;\n\nConsole.WriteLine(apple.Map(CreateMessage).Unwrap(\"No fruit\")); // \"The fruit is a apple\"\nConsole.WriteLine(noFruit.Map(CreateMessage).Unwrap(\"No fruit\")); // \"No fruit\"\n```\n\n#### Select\n\n**Alias**: `Maybe.Select()` is an alias of `Maybe.Map()`\n\n#### Bind\n\nUse case: Transforming from one Maybe into another Maybe\n(like `Maybe.Map` but it transforms the Maybe instead of the inner value)\n\n**Note**: the delegate (ex `MakeAppleSauce`) passed to `Maybe.Bind()` is only executed if the Maybe has an inner value\n\n```csharp\nMaybe\u003cstring\u003e MakeAppleSauce(Maybe\u003cstring\u003e fruit)\n{\n    if (fruit == \"apple\") // we can only make applesauce from apples 🍎\n    {\n        return \"applesauce\";\n    }\n\n    return Maybe\u003cstring\u003e.None;\n}\n\nMaybe\u003cstring\u003e apple = \"apple\";\nMaybe\u003cstring\u003e banana = \"banana\";\nMaybe\u003cstring\u003e noFruit = Maybe\u003cstring\u003e.None;\n\nConsole.WriteLine(apple.Bind(MakeAppleSauce).ToString()); // \"applesauce\"\nConsole.WriteLine(banana.Bind(MakeAppleSauce).ToString()); // \"No value\"\nConsole.WriteLine(noFruit.Bind(MakeAppleSauce).ToString()); // \"No value\"\n```\n\n#### SelectMany\n\n**Alias**: `Maybe.SelectMany()` is an alias of `Maybe.Bind()`\n\n#### Choose\n\nUse case: Filter a collection of Maybes to only the ones that have a value,\nand then return the value for each, or map that value to a new one\n\n**Note**: the delegate passed to `Maybe.Choose()` is only executed on the Maybes of the collection with an inner value\n\n```csharp\nIEnumerable\u003cMaybe\u003cstring\u003e\u003e unknownFruits = new[] { \"apple\", Maybe\u003cstring\u003e.None, \"banana\" };\n\nIEnumerable\u003cstring\u003e knownFruits = unknownFruits.Choose();\nIEnumerable\u003cstring\u003e fruitResponses = unknownFruits.Choose(fruit =\u003e $\"Delicious {fruit}\");\n\nConsole.WriteLine(string.Join(\", \", knownFruits)) // \"apple, banana\"\nConsole.WriteLine(string.Join(\", \", fruitResponses)) // \"Delicious apple, Delicious banana\"\n```\n\n#### Execute\n\nUse case: Safely executing a `void` (or `Task`) returning operation on the Maybe inner value\nwithout checking if there is one\n\n**Note**: the `Action` (ex `PrintFruit`) passed to `Maybe.Execute()` is only executed if the Maybe has an inner value\n\n```csharp\nvoid PrintFruit(string fruit)\n{\n    Console.WriteLine($\"This is a {fruit}\");\n}\n\nMaybe\u003cstring\u003e apple = \"apple\";\nMaybe\u003cstring\u003e noFruit = Maybe\u003cstring\u003e.None;\n\napple.Execute(PrintFruit); // \"This is a apple\"\nnoFruit.Execute(PrintFruit); // no output to the console\n```\n\n#### ExecuteNoValue\n\nUse case: Executing a `void` (or `Task`) returning operation when the Maybe has no value\n\n```csharp\nvoid LogNoFruit(string fruit)\n{\n    Console.WriteLine($\"There are no {fruit}\");\n}\n\nMaybe\u003cstring\u003e apple = \"apple\";\nMaybe\u003cstring\u003e banana = Maybe\u003cstring\u003e.None;\n\napple.ExecuteNoValue(() =\u003e LogNoFruit(\"apple\")); // no output to console\nbanana.ExecuteNoValue(() =\u003e LogNoFruit(\"banana\")); // \"There are no banana\"\n```\n\n#### Or\n\nUse case: Supplying a fallback value Maybe or value in the case that the Maybe has no inner value\n\n**Note**: The fallback `Func\u003cT\u003e` (ex `() =\u003e \"banana\"`) will only be executed\nif the Maybe has no inner value\n\n```csharp\nMaybe\u003cstring\u003e apple = \"apple\";\nMaybe\u003cstring\u003e banana = \"banana\";\nMaybe\u003cstring\u003e noFruit = Maybe\u003cstring\u003e.None;\n\nConsole.WriteLine(apple.Or(banana).ToString()); // \"apple\"\nConsole.WriteLine(noFruit.Or(() =\u003e banana)).ToString()); // \"banana\"\nConsole.WriteLine(noFruit.Or(\"banana\").ToString()); // \"banana\"\nConsole.WriteLine(noFruit.Or(() =\u003e \"banana\").ToString()); // \"banana\"\n```\n\n#### Match\n\nUse case: Defining two operations to perform on a Maybe.\nOne to be executed if there is an inner value, and the other to executed if there is not\n\n```csharp\nMaybe\u003cstring\u003e apple = \"apple\";\nMaybe\u003cstring\u003e noFruit = Maybe\u003cstring\u003e.None;\n\n// Void returning Match\napple.Match(\n    fruit =\u003e Console.WriteLine($\"It's a {fruit}\"),\n    () =\u003e Console.WriteLine(\"There's no fruit\"));\n\n// Mapping Match\nstring fruitMessage = noFruit.Match(\n    fruit =\u003e $\"It's a {fruit}\",\n    () =\u003e \"There's no fruit\"));\n\nConsole.WriteLine(fruitMessage); // \"There's no fruit\"\n```\n\n#### TryFirst and TryLast\n\nUse case: Replacing `.FirstOrDefault()` and `.LastOrDefault()` so that you can return a\nMaybe instead of a `null` or value type default value (like `0`, `false`) when working with collections\n\n```csharp\nIEnumerable\u003cstring\u003e fruits = new[] { \"apple\", \"coconut\", \"banana\" };\n\nMaybe\u003cstring\u003e firstFruit = fruits.TryFirst();\nMaybe\u003cstring\u003e probablyABanana = fruits.TryFirst(fruit =\u003e fruit.StartsWith(\"ba\"));\nMaybe\u003cstring\u003e aPeachOrAPear = fruits.TryFirst(fruit =\u003e fruit.StartsWith(\"p\"));\n\nConsole.WriteLine(firstFruit.ToString()); // \"apple\"\nConsole.WriteLine(probablyABanana.ToString()); // \"banana\"\nConsole.WriteLine(aPeachOrAPear.ToString()); // \"No value\"\n\nMaybe\u003cstring\u003e lastFruit = fruits.TryLast();\nMaybe\u003cstring\u003e anAppleOrApricot = fruits.TryLast(fruit =\u003e fruit.StartsWith(\"a\"));\n\nConsole.WriteLine(lastFruit.ToString()); // \"banana\"\nConsole.WriteLine(anAppleOrApricot.ToString()); // \"apple\"\n```\n\n#### TryFind\n\nUse case: Safely getting a value out of a Dictionary\n\n```csharp\nDictionary\u003cstring, int\u003e fruitInventory = new()\n{\n    { \"apple\", 10 },\n    { \"banana\", 2 }\n};\n\nMaybe\u003cint\u003e appleCount = fruitInventory.TryFind(\"apple\");\nMaybe\u003cint\u003e kiwiCount = fruitInventory.TryFind(\"kiwi\");\n\nConsole.WriteLine(appleCount.ToString()); // \"10\"\nConsole.WriteLine(kiwiCount.ToString()); // \"No value\"\n```\n\n#### ToResult\n\nUse case: Representing the lack of an inner value in a Maybe as a failed operation\n\n**Note**: See `Result` section below\n\n```csharp\nMaybe\u003cstring\u003e fruit = \"banana\";\nMaybe\u003cstring\u003e noFruit = Maybe\u003cstring\u003e.None;\n\nstring errorMessage = \"There was no fruit to give\";\n\nResult\u003cstring\u003e weGotAFruit = fruit.ToResult(errorMessage);\nResult\u003cstring\u003e failedToGetAFruit = noFruit.ToResult(errorMessage);\n\nConsole.WriteLine(weGotAFruit.Value); // \"banana\"\nConsole.WriteLine(failedToGetAFruit.Error); // \"There was no fruit to give\"\n```\n\n#### ToUnitResult\n\nUse case: Representing the lack of an inner value in a Maybe as a failed operation, if an Error is provided\n\nUse case: Representing the presence of an inner value in a Maybe as a failed operation\n\n**Note**: See `UnitResult` section below\n\n```csharp\nMaybe\u003cError\u003e error = new Error();\nMaybe\u003cstring\u003e noFruit = Maybe\u003cstring\u003e.None;\n\nUnitResult\u003cError\u003e weGotAnError = error.ToUnitResult();\nUnitResult\u003cError\u003e failedToGetAFruit = noFruit.ToUnitResult(new Error());\n\nConsole.WriteLine(weGotAnError.IsFailure); // true\nConsole.WriteLine(failedToGetAFruit.IsFailure); // true\n```\n\n### Result\n\n#### Explicit Construction: Success and Failure\n\nUse case: Creating a new Result in a Success or Failure state\n\n```csharp\nrecord FruitInventory(string Name, int Count);\n\nResult\u003cFruitInventory\u003e appleInventory = Result.Success(new FruitInventory(\"apple\", 4));\nResult\u003cFruitInventory\u003e failedOperation = Result.Failure\u003cFruitInventory\u003e(\"Could not find inventory\");\nResult successInventoryUpdate = Result.Success();\n```\n\nTo create a success result of a value you can also use the `Of` method which has overloads for `Func\u003cT\u003e` and `Task\u003cT\u003e`.\n\n```csharp\nResult\u003cSomething\u003e something = Result.Of(_service.CreateSomething());\nResult\u003cSomething\u003e something = await Result.Of(_service.CreateSomethingAsync());\nResult\u003cSomething\u003e something = Result.Of(() =\u003e _service.CreateSomething());\nResult\u003cSomething\u003e something = await Result.Of(() =\u003e _service.CreateSomethingAsync());\n```\n\n#### Conditional Construction: SuccessIf and FailureIf\n\nUse case: Creating successful or failed Results based on expressions or delegates instead of if/else statements or ternary expressions\n\n```csharp\nbool onTropicalIsland = true;\n\nResult foundCoconut = Result.SuccessIf(onTropicalIsland, \"These trees seem bare 🥥\");\nResult foundGrapes = Result.FailureIf(() =\u003e onTropicalIsland, \"No grapes 🍇 here\");\n\n// or\n\nbool isNewShipmentDay = true;\n\nResult\u003cFruitInventory\u003e appleInventory = Result.SuccessIf(isNewShipmentDay, new FruitInventory(\"apple\", 4), \"No 🍎 today\");\nResult\u003cFruitInventory\u003e bananaInventory = Result.SuccessIf(() =\u003e isNewShipmentDay, new FruitInventory(\"banana\", 2), \"All out of 🍌\");\n\n// or\n\nbool afterBreakfast = true;\n\nResult\u003cFruitInventory\u003e orangeInventory = Result.FailureIf(afterBreakfast, new FruitInventory(\"orange\", 10), \"No 🍊 today\");\nResult\u003cFruitInventory\u003e grapefruitInventory = Result.FailureIf(() =\u003e afterBreakfast, new FruitInventory(\"grapefruit\", 5), \"No grapefruit 😢\");\n```\n\n#### Implicit Conversion\n\nUse case: Easily creating a successful result from a value\n\n```csharp\nResult\u003cFruitInventory\u003e appleInventory = new FruitInventory(\"apple\", 4);\nResult failedInventoryUpdate = \"Could not update inventory\";\n```\n\n#### ToString\n\nUse case: Printing out the state of a Result and its inner value or error\n\n```csharp\nResult\u003cFruitInventory\u003e appleInventory = new FruitInventory(\"apple\", 4);\nResult\u003cFruitInventory\u003e bananaInventory = Result.Failure\u003cFruitInventory\u003e(\"Could not find any bananas\");\nResult failedInventoryUpdate = \"Could not update inventory\";\nResult successfulInventoryUpdate = Result.Success();\n\nConsole.WriteLine(appleInventory.ToString()); // \"Success(FruitInventory { Name = apple, Count = 4 })\"\nConsole.WriteLine(bananaInventory.ToString()); // \"Failure(Could not find any bananas)\"\nConsole.WriteLine(failedInventoryUpdate.ToString()); // \"Failure(Could not update inventory)\"\nConsole.WriteLine(successfulInventoryUpdate.ToString()); // \"Success\"\n```\n\n#### Map\n\nUse case: Transforming the inner value of a successful Result, without needing to check on\nthe success/failure state of the Result\n\n**Note**: the delegate (ex `CreateMessage`) passed to `Result.Map()` is only executed if the Result was successful\n\n```csharp\nstring CreateMessage(FruitInventory inventory)\n{\n    return $\"There are {inventory.Count} {inventory.Name}(s)\";\n}\n\nResult\u003cFruitInventory\u003e appleInventory = new FruitInventory(\"apple\", 4);\nResult\u003cFruitInventory\u003e bananaInventory = Result.Failure\u003cFruitInventory\u003e(\"Could not find any bananas\");\n\nConsole.WriteLine(appleInventory.Map(CreateMessage).ToString()); // \"Success(There are 4 apple(s))\"\nConsole.WriteLine(bananaInventory.Map(CreateMessage).ToString()); // \"Failure(Could not find any bananas)\"\n```\n\n#### MapError\n\nUse case: Transforming the inner error of a failed Result, without needing to check on\nthe success/failure state of the Result\n\n**Note**: the delegate (ex `ErrorEnhancer`) passed to `Result.MapError()` is only executed if the Result failed\n\n```csharp\nstring ErrorEnhancer(string errorMessage)\n{\n    return $\"Failed operation: {errorMessage}\";\n}\n\nConsole.WriteLine(appleInventory.MapError(ErrorEnhancer).ToString()); // \"Success(FruitInventory { Name = apple, Count = 4 })\"\nConsole.WriteLine(bananaInventory.MapError(ErrorEnhancer).ToString()); // \"Failed operation: Could not find any bananas\"\n```\n\n## Testing\n\n### CSharpFunctionalExtensions.FluentAssertions\n\nA small set of extensions to make test assertions more fluent when using CSharpFunctionalExtensions! Check out the [repo for this library](https://github.com/NitroDevs/CSharpFunctionalExtensions.FluentAssertions) more information!\n\nIncludes custom assertions for\n- Maybe\n- Result\n- Result\u003cT\u003e\n- Result\u003cT, E\u003e\n- UnitResult\n\n#### Example\n\n```csharp\nvar result = Result.Success(420);\n\nresult.Should().Succeed(); // passes\nresult.Should().SucceedWith(420); // passes\nresult.Should().SucceedWith(69); // throws\nresult.Should().Fail(); // throws\n```\n\n## Analyzers\n\n### [CSharpFunctionalExtensions.Analyzers](https://github.com/AlmarAubel/CSharpFunctionalExtensions.Analyzers)\nA Roslyn analyzer package that provides warnings and recommendations to prevent misuse of `Result` objects in `CSharpFunctionalExtensions`. Ensures more robust implementation when working with Result types.\n\nAvailable on [NuGet](https://www.nuget.org/packages/CSharpFunctionalExtensions.Analyzers)\n```bash\ndotnet add package CSharpFunctionalExtensions.Analyzers\n```\n\n## Read or Watch more about these ideas\n\n- [Functional C#: Primitive obsession](https://enterprisecraftsmanship.com/2015/03/07/functional-c-primitive-obsession/)\n- [Functional C#: Non-nullable reference types](https://enterprisecraftsmanship.com/2015/03/13/functional-c-non-nullable-reference-types/)\n- [Functional C#: Handling failures, input errors](https://enterprisecraftsmanship.com/2015/03/20/functional-c-handling-failures-input-errors/)\n- [Applying Functional Principles in C# Pluralsight course](https://enterprisecraftsmanship.com/ps-func)\n\n## Related Projects\n\n- [Typescript Functional Extensions](https://github.com/seangwright/typescript-functional-extensions)\n- [UniTask extensions for Unity](https://github.com/Razenpok/CSharpFunctionalExtensions.UniTask)\n\n## Contributors\n\nA big thanks to the project contributors!\n\n- [Rory Sánchez](https://github.com/RorySan)\n- [Chris C](https://github.com/ToInvertedResult)\n- [Marcin Jahn](https://github.com/marcinjahn)\n- [Jannes Kaspar-Müller](https://github.com/JKamue)\n- [dbuckin1](https://github.com/dbuckin1)\n- [bothzoli](https://github.com/bothzoli)\n- [Pavel Zemlianikin](https://github.com/PNZeml)\n- [Simon Lang](https://github.com/redx177)\n- [Nils Vreman](https://github.com/NilsVreman)\n- [Scheichsbeutel](https://github.com/Scheichsbeutel)\n- [Alexey Malinin](https://github.com/TechnoBerry)\n- [Robert Larkins](https://github.com/robertlarkins)\n- [tinytownsoftware](https://github.com/tinytownsoftware)\n- [piotr121993](https://github.com/piotr121993)\n- [Dmitry Korotin](https://github.com/teheran)\n- [michalsznajder](https://github.com/michalsznajder)\n- [Xavier](https://github.com/xavierjohn)\n- [Julien Aspirot](https://github.com/julienasp)\n- [Kyle McMaster](https://github.com/KyleMcMaster)\n- [Vinícius Beloni Cubas](https://github.com/vinibeloni)\n- [rutkowskit](https://github.com/rutkowskit)\n- [Giovanni Costagliola](https://github.com/MrBogomips)\n- [Mark Wainwright](https://github.com/wainwrightmark)\n- [ProphetLamb](https://github.com/ProphetLamb)\n- [Paul Williams](https://github.com/Paul-Williams)\n- [alexmurari](https://github.com/alexmurari)\n- [ruud](https://github.com/ruudhe)\n- [Tomasz Malinowski](https://github.com/Yaevh)\n- [Staffan Wingren](https://github.com/staffanwingren)\n- [Tim Schneider](https://github.com/DerStimmler)\n- [Piotr Karasiński](https://github.com/Caleb9)\n- [Marcel Roozekrans](https://github.com/MarcelRoozekrans)\n- [guythetechie](https://github.com/guythetechie)\n- [Logan Kahler](https://github.com/lqkahler)\n- [Ali Khalili](https://github.com/AliKhalili)\n- [Andrei Andreev](https://github.com/Razenpok)\n- [YudApps](https://github.com/YudApps)\n- [dataphysix](https://github.com/dataphysix)\n- [Laszlo Lueck](https://github.com/LaszloLueck)\n- [Sean G. Wright](https://github.com/seangwright)\n- [Samuel Viesselman](https://github.com/SamuelViesselman)\n- [Stian Kroknes](https://github.com/stiankroknes)\n- [dataneo](https://github.com/dataneodev)\n- [michaeldileo](https://github.com/michaeldileo)\n- [Renato Ramos Nascimento](https://github.com/renato04)\n- [Patrick Drechsler](https://github.com/draptik)\n- [Vadim Mingazhev](https://github.com/mingazhev)\n- [Darick Carpenter](https://github.com/darickc)\n- [Stéphane Mitermite](https://github.com/kakone)\n- [Markus Nißl](https://github.com/mnissl)\n- [Adrian Frielinghaus](https://github.com/freever)\n- [svroonland](https://github.com/svroonland)\n- [JvSSD](https://github.com/JvSSD)\n- [Vladimir Makaev](https://github.com/VladimirMakaev)\n- [Ben Smith](https://github.com/benprime)\n- [pedromtcosta](https://github.com/pedromtcosta)\n- [Michał Bator](https://github.com/MikelThief)\n- [mukmyash](https://github.com/mukmyash)\n- [azm102](https://github.com/azm102)\n- [ThomasDC](https://github.com/thomasdc)\n- [bopazyn](https://github.com/bopazyn)\n- [Joris Goovaerts](https://github.com/CommCody)\n- [Ivan Deev](https://github.com/BillyFromAHill)\n- [Damian Płaza](https://github.com/dpraimeyuu)\n- [ergwun](https://github.com/ergwun)\n- [Michael DiLeo](https://github.com/pilotMike)\n- [Jean-Claude](https://github.com/jcsonder)\n- [Matt Jenkins](https://github.com/space-alien)\n- [Michael Altmann](https://github.com/altmann)\n- [Steven Giesel](https://github.com/linkdotnet)\n- [Anton Hryshchanka](https://github.com/ahryshchanka)\n- [Mikhail Bashurov](https://github.com/saitonakamura)\n- [kostekk88](https://github.com/kostekk88)\n- [Carl Abrahams](https://github.com/CarlHA)\n- [golavr](https://github.com/golavr)\n- [Sviataslau Hankovich](https://github.com/hankovich)\n- [Chad Gilbert](https://github.com/freakingawesome)\n- [Robert Sęk](https://github.com/robosek)\n- [Sergey Solomentsev](https://github.com/SergAtGitHub)\n- [Malcolm J Harwood](https://github.com/mjharwood)\n- [Dragan Stepanovic](https://github.com/dragan-stepanovic)\n- [Ivan Novikov](https://github.com/jonny-novikov)\n- [Denis Molokanov](https://github.com/dmolokanov)\n- [Gerald Wiltse](https://github.com/solvingJ)\n- [yakimovim](https://github.com/yakimovim)\n- [Alex Erygin](https://github.com/alex-erygin)\n- [Omar Aloraini](https://github.com/omaraloraini)\n","funding_links":[],"categories":["Frameworks, Libraries and Tools","C\\#","csharp","C# #","Results Objects Pattern (Discriminate Unions + Functional Programming)","Libraries, Frameworks and Tools","框架, 库和工具","Functional Programming"],"sub_categories":["Functional Programming","响应式编程"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvkhorikov%2FCSharpFunctionalExtensions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvkhorikov%2FCSharpFunctionalExtensions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvkhorikov%2FCSharpFunctionalExtensions/lists"}