func

所属分类:C#编程
开发工具:C#
文件大小:0KB
下载次数:0
上传日期:2023-10-18 15:39:11
上 传 者sh-1993
说明:  扩展C#函数编程功能的库,
(Library to extend C# s functional programming capabilities,)

文件列表:
CODE_OF_CONDUCT.md (3352, 2023-10-18)
Func.UnitTests/ (0, 2023-10-18)
Func.UnitTests/CurryingTests.cs (20080, 2023-10-18)
Func.UnitTests/CurryingTests.tt (2527, 2023-10-18)
Func.UnitTests/Func.UnitTests.csproj (4532, 2023-10-18)
Func.UnitTests/MapExtensionMethodsArgumentAdditionsTests.cs (6095, 2023-10-18)
Func.UnitTests/MapExtensionMethodsArgumentAdditionsTests.tt (2366, 2023-10-18)
Func.UnitTests/MapExtensionMethodsTests.cs (1218, 2023-10-18)
Func.UnitTests/OptionTests.cs (1705, 2023-10-18)
Func.UnitTests/ResultArgumentAdditionsTests.cs (29465, 2023-10-18)
Func.UnitTests/ResultArgumentAdditionsTests.tt (6620, 2023-10-18)
Func.UnitTests/ResultChainingExtensionMethodsTests.cs (3760, 2023-10-18)
Func.UnitTests/ResultMapExtensionArgumentAdditionsTests.cs (6663, 2023-10-18)
Func.UnitTests/ResultMapExtensionArgumentAdditionsTests.tt (2507, 2023-10-18)
Func.UnitTests/ResultMapExtensionMethodsTests.cs (1430, 2023-10-18)
Func.UnitTests/ResultTests.cs (30215, 2023-10-18)
Func.UnitTests/TeeExtensionMethodsArgumentAdditionsTests.cs (18305, 2023-10-18)
Func.UnitTests/TeeExtensionMethodsArgumentAdditionsTests.tt (5118, 2023-10-18)
Func.UnitTests/TeeExtensionMethodsTests.cs (2650, 2023-10-18)
Func.UnitTests/UnionTests.cs (58026, 2023-10-18)
Func.UnitTests/UnionTests.tt (1862, 2023-10-18)
Func/ (0, 2023-10-18)
Func/Currying.cs (18465, 2023-10-18)
Func/Currying.tt (2046, 2023-10-18)
Func/EnumerableExtensionMethods.cs (580, 2023-10-18)
Func/Func.csproj (4510, 2023-10-18)
Func/Func.csproj.DotSettings (565, 2023-10-18)
Func/MapExtensionMethods.cs (7885, 2023-10-18)
Func/MapExtensionMethods.tt (2627, 2023-10-18)
Func/Options/ (0, 2023-10-18)
Func/Options/None.cs (813, 2023-10-18)
Func/Options/Option.cs (792, 2023-10-18)
Func/Options/Some.cs (1226, 2023-10-18)
Func/PartialApplicationDelegates.cs (3462, 2023-10-18)
Func/PartialApplicationDelegates.tt (806, 2023-10-18)
... ...

# Func [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/awsxdr/Func/blob/master/LICENSE) ![Release](https://github.com/awsxdr/func/workflows/Release/badge.svg) ![CI](https://github.com/awsxdr/func/workflows/CI/badge.svg?branch=develop) Func is a library designed to expand C#'s functional programming capabilities. ## Contents * [Usage](#usage) * [Map & Tee](#map-and-tee) * [Options](#options) * [Railway-oriented programming](#railway-oriented-programming-result) ## Usage ### Map and Tee `Map` and `Tee` are methods used to chain method calls. They can be thought of as equivalent to `Select` and `ForEach` but operating on single items. `Map` takes in a value, executes a given function on it and returns the result. This is similar to the behaviour of the `|>` operator in F#. `Tee` takes in a value, executes a given method, and returns the original value. ```csharp using Func; public class Example { private readonly ILogger _logger; public Example(ILogger logger) => _logger = logger; public string GetWelcomeMessage() => GetCurrentUserId() .Tee(id => _logger.LogInformation("Generating welcome message for user {0}", id)) .Map(GetUserNameFromId) .Map(GetWelcomeMessageForUserName); private int GetCurrentUserId() => 123; private string GetUserNameFromId(int id) => "Test User"; private string GetWelcomeMessageForUserName(string userName) => $"Hello, {userName}"; } ``` #### Asynchronous operations `Map` and `Tee` are designed to work happily with asynchronous functions returning `Task` objects. Methods returning tasks which are chained together will return a single unified task. ```csharp using Func; public class Example { private readonly ILogger _logger; public Example(ILogger logger) => _logger = logger; public async Task GetWelcomeMessage() => await GetCurrentUserId() .Tee((int id) => _logger.LogInformation("Generating welcome message for user {0}", id)) .Map(GetUserNameFromId) .Map(GetWelcomeMessageForUserName); private Task GetCurrentUserId() => Task.FromResult(123); private Task GetUserNameFromId(int id) => Task.FromResult("Test User"); private string GetWelcomeMessageForUserName(string userName) => $"Hello, {userName}"; } ``` Here, several methods are chained together; some of them returning tasks, some not. A single `Task` is returned which performs all of the chained actions. Of note here is the use of `int` on `Tee`. Generally the compiler will be able to infer the types being used, but in cases like this where the argument is of type `object` a type needs specifying. If you encounter these sort of errors you can provide the types or, perhaps preferably, provide a more strongly typed method to call. #### Multiple arguments `Map` and `Tee` support methods with up to 15 arguments. Additional arguments are provided as parameters to `Map` and `Tee` following the method. The value that `Map` or `Tee` is acting on is always passed as the last argument. In the following example, we call `string.Join` which has the signature `string Join(string separator, IEnumerable values)`. `Map` is called on the string array and the separator is passed as an argument to `Map`. ```csharp public class Example { public void OutputUserNames() => GetUserNames() .Map(string.Join, ", ") .Tee(Console.WriteLine); private IEnumerable GetUserNames() => new[] { "Anne", "Brian", "Claire", "Daniel" }; } ``` ### Option Options represent a way of marking a value as optional. Optional items offer benefits over nullable items because they enforce checking for a value and thus remove the possibility of ending up with the dreaded `NullReferenceException`s. ```csharp using static Func.Option; public class Example { public static string GetDescription(Option value) => value switch { Some x when x.Value > 10 => "Huge", Some x when x.Value > 5 => "Big", Some x when x.Value < 1 => "Tiny", Some x when x.Value < 5 => "Small", Some _ => "Average", None _ => "Empty", _ => "Unexpected!" }; public void Test() { _ = GetDescription(Some(11)); // "Huge" _ = GetDescription(Some(3)); // "Small" _ = GetDescription(None()); // "Empty" } } ``` The above example shows a function which expects either an integer or nothing. The `Value` property can only be retrieved once the `Option` has been cast to `Some`. Also supported is passing values when the type isn't specified. In the below example, any type can be passed in. ```csharp using static Func.Option; public class Example { public static string GetDescription(Option value) => value switch { Some _ => "Number", Some _ => "Number", Some _ => "Text", Some _ => "Something else", None _ => "Empty", _ => "Unexpected!" }; public void Test() { GetDescription(Some(11)); // "Number" GetDescription(Some(8.42)); // "Number" GetDescription(Some("Hello")); // "Text" GetDescription(Some(false)); // "Something else" GetDescription(None()); // "Empty" } } ``` ### Result Func supports result types which can be returned from functions to indicate success or failure. Functions which return a `Result` object can be chained together with calls to `Then`, `And`, or `Else`. If any method in the chain fails then the chain stops executing and a fail is returned. The concept is similar to Javascript's promises or Rust's `Result` type. The aim of results is to prevent the use of exceptions for program flow. Methods can fail on non-exceptional errors to avoid continuing without the overhead of throwing an exception. ```csharp using System; using System.Threading.Tasks; using Func; using static Func.Result; public class Example { private readonly ILogger _logger; public Example(ILogger logger) => _logger = logger; public async Task GetWelcomeMessage(string username) => await GetCurrentUserId(username) .Then(GetUserFullNameFromId) .Then(GetWelcomeMessageForUserFullName) .OnSuccess(() => _logger.LogInformation($"User {username} found")) .OnError((UserNotFoundError e) => { _logger.LogWarn($"User {username} not found"); }) .OnError(() => _logger.LogWarn("Something went very wrong!")) switch { Success s => s.Value, Failure _ => "User could not be found", Failure _ => throw new Exception("Unexpected error occurred getting welcome message for user") }; private Task> GetCurrentUserId(string username) => (username == "test" ? Succeed(123) : Result.Fail(new UserNotFoundError()) ).ToTask(); private Task> GetUserFullNameFromId(int id) => Succeed("Test User").ToTask(); private Result GetWelcomeMessageForUserFullName(string userFullName) => Succeed($"Hello, {userFullName}"); } public class UserNotFoundError : ResultError { } ``` Note here that the call to `Fail` requires the result types to be passed. This is because the types can't be inferred. Also note that the error type is specified in the lambda for `OnError`. If not specified here then the method would require both the error type and result type specified in angular brackets. ### Union A `Union` is used to represent a value which can be one of several types. To determine what type is held by the union, either use the `Is<>` method, or use the `is` keyword on the `Value` property. This has a lot of similarities to `Option` but constrains the types which are stored. The following example is to show how unions are used. However, it would likely be better to use overloaded methods for this specific case. ```csharp using static Func.Result; public class Example { public static Result GetDescription(Union value) => (value.Value switch { Some x => Succeed(x.Value), Some x => Succeed((int)x.Value), Some x => int.TryParse(x.Value, out var i) ? Succeed(i) : Result.Fail(), _ => throw new Exception("Unexpected type") }) .ThenMap(x => x > 10 ? "Huge" : x > 5 ? "Big" : x< 1 ? "Tiny" : x< 5 ? "Small" : "Average" ); public void Test() { GetDescription(11); // Success - "Huge" GetDescription(8.42); // Success - "Big" GetDescription("2"); // Success - "Small" GetDescription("Hello"); // Failure } public class FormatError : ResultError {} } ```

近期下载者

相关文件


收藏者