{"id":13415213,"url":"https://github.com/nlkl/Optional","last_synced_at":"2025-03-14T22:33:04.162Z","repository":{"id":24325971,"uuid":"27722798","full_name":"nlkl/Optional","owner":"nlkl","description":"A robust option type for C#","archived":false,"fork":false,"pushed_at":"2023-08-31T16:00:28.000Z","size":8410,"stargazers_count":884,"open_issues_count":26,"forks_count":75,"subscribers_count":34,"default_branch":"master","last_synced_at":"2024-05-30T00:54:17.414Z","etag":null,"topics":["functional-programming","option-type","safety"],"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/nlkl.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}},"created_at":"2014-12-08T16:04:56.000Z","updated_at":"2024-05-28T07:56:51.000Z","dependencies_parsed_at":"2022-08-07T11:01:00.047Z","dependency_job_id":"0d9439a7-c9b8-43e0-bfa0-7980d993ee79","html_url":"https://github.com/nlkl/Optional","commit_stats":{"total_commits":204,"total_committers":11,"mean_commits":"18.545454545454547","dds":"0.20588235294117652","last_synced_commit":"fa0160d995af60e8378c28005d810ec5b74f2eef"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nlkl%2FOptional","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nlkl%2FOptional/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nlkl%2FOptional/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nlkl%2FOptional/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nlkl","download_url":"https://codeload.github.com/nlkl/Optional/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243161144,"owners_count":20246012,"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":["functional-programming","option-type","safety"],"created_at":"2024-07-30T21:00:45.201Z","updated_at":"2025-03-14T22:33:04.154Z","avatar_url":"https://github.com/nlkl.png","language":"C#","readme":"![Optional](https://raw.githubusercontent.com/nlkl/Optional/master/icon/Logo.png)\n\nOptional is a robust option/maybe type for C#.\n\nVersion: 4.0.0\n\n## What and Why?\n\nOptional is a strongly typed alternative to null values that lets you:\n\n* Avoid those pesky null-reference exceptions\n* Signal intent and model your data more explictly\n* Cut down on manual null checks and focus on your domain\n\n## Features\n\n* Robust and well tested\n* Self contained with no dependencies\n* Easily installed through NuGet\n* Supports **.NET 3.5+** and **.NET Core** (.NET Standard 1.0+)\n* Focused but full-featured API\n\n## Installation\n\nSimply reference Optional.dll and you are good to go!\n\nOptional is also available via NuGet:\n\n```\nPM\u003e Install-Package Optional \n```\n\nOr visit: [https://www.nuget.org/packages/Optional/](https://www.nuget.org/packages/Optional/)\n\n## Core concepts\n\nThe core concept behind Optional is derived from two common functional programming constructs, typically referred to as a maybe type and an either type (referred to as `Option\u003cT\u003e` and `Option\u003cT, TException\u003e` in Optional).\n\nMany functional programming languages disallow null values, as null-references can introduce hard-to-find bugs. A maybe type is a type-safe alternative to null values. \n\nIn general, an optional value can be in one of two states: Some (representing the presence of a value) and None (representing the lack of a value). Unlike null, an option type forces the user to check if a value is actually present, thereby mitigating many of the problems of null values. `Option\u003cT\u003e` is a struct in Optional, making it impossible to assign a null value to an option itself.\n\nFurther, an option type is a lot more explicit than a null value, which can make APIs based on optional values a lot easier to understand. Now, the type signature will indicate if a value can be missing!\n\nAn either type is conceptually similar to a maybe type. Whereas a maybe type only indicates if a value is present or not, an either type contains an auxiliary value describing how an operation failed. Apart from this *exceptional* value, an either-type behaves much like its simpler counterpart.\n\nWorking with maybe and either types is very similar, and the description below will therefore focus on the maybe type, and only provide a quick summary for the either type.\n\nFinally, Optional offers several utility methods that make it easy and convenient to work with both of the above described optional values.\n\n## Usage\n\n### Using the library\n\nTo use Optional simply import the following namespace:\n\n```csharp\nusing Optional;\n```\n\nA few auxiliary namespaces are provided:\n\n```csharp\nusing Optional.Linq; // Linq query syntax support\nusing Optional.Unsafe; // Unsafe value retrieval\n```\n\n### Creating optional values\n\nThe most basic way to create optional values is to use the static `Option` class:\n\n```csharp\nvar none = Option.None\u003cint\u003e();\nvar some = Option.Some(10);\n```\n\nFor convenience, a set of extension methods are provided to make this a little less verbose:\n\n```csharp\nvar none = 10.None(); // Creates a None value, with 10 determining its type (int)\nvar some = 10.Some();\n```\n\nNote that it is also allowed (but hardly recommended) to wrap null values in an Option instance:\n\n```csharp\nstring nullString = null;\nvar someWithNull = nullString.Some();\n```\n\nTo make it easier to filter away such null values, a specialized extension method is provided:\n\n```csharp\nstring nullString = null;\nvar none = nullString.SomeNotNull(); // Returns None if original value is null\n```\n\nSimilarly, a more general extension method is provided, allowing a specified predicate:\n\n```csharp\nstring str = \"abc\";\nvar none = str.SomeWhen(s =\u003e s == \"cba\"); // Return None if predicate is violated\nvar none = str.NoneWhen(s =\u003e s == \"abc\"); // Return None if predicate is satisfied\n```\n\nClearly, optional values are conceptually quite similar to nullables. Hence, a method is provided to convert a nullable into an optional value:\n\n```csharp\nint? nullableWithoutValue = null;\nint? nullableWithValue = 2;\nvar none = nullableWithoutValue.ToOption();\nvar some = nullableWithValue.ToOption();\n```\n\n### Retrieving values\n\nWhen retrieving values, Optional forces you to consider both cases (that is if a value is present or not).\n\nFirstly, it is possible to check if a value is actually present:\n\n```csharp\nvar hasValue = option.HasValue;\n```\n\nIf you want to check if an option contains a specific value, you can use the `Contains` or `Exists` methods. The former checks if the optional contains a specified value, the latter if the contained value satisfies some predicate:\n\n```csharp\nvar isThousand = option.Contains(1000);\nvar isGreaterThanThousand = option.Exists(val =\u003e val \u003e 1000);\n```\n\nThe most basic way to retrieve a value from an `Option\u003cT\u003e` is the following:\n\n```csharp\n// Returns the value if present, or otherwise an alternative value (10)\nvar value = option.ValueOr(10);\nvar value = option.ValueOr(() =\u003e SlowOperation());  // Lazy variant\n```\n\nIn more elaborate scenarios, the `Match` method evaluates a specified function:\n\n```csharp\n// Evaluates one of the provided functions and returns the result\nvar value = option.Match(x =\u003e x + 1, () =\u003e 10); \n\n// Or written in a more functional'ish style (think pattern matching)\nvar value = option.Match(\n  some: x =\u003e x + 1, \n  none: () =\u003e 10\n);\n```\n\nThere is a similar `Match` function to simply induce side-effects:\n\n```csharp\n// Evaluates one of the provided actions\noption.Match(x =\u003e Console.WriteLine(x), () =\u003e Console.WriteLine(10)); \n\n// Or pattern matching'ish as before\noption.Match(\n  some: x =\u003e Console.WriteLine(x), \n  none: () =\u003e Console.WriteLine(10)\n);\n```\n\nFinally, side-effect matching (that is matching without returning a value) can be carried out for each case separately:\n\n```csharp\n// Evaluated if the value is present\noption.MatchSome(x =\u003e \n{\n    Console.WriteLine(x)\n});\n\n// Evaluated if the value is absent\noption.MatchNone(() =\u003e \n{\n    Console.WriteLine(\"Not found\") \n});\n```\n\n### Retrieving values without safety\n\nIn some cases you might be absolutely sure that a value is present. Alternatively, the lack of a value might be fatal to your program, in which case you just want to indicate such a failure.\n\nIn such scenarios, Optional allows you to drive without a seatbelt. However, to stress the lack safety, another namespace needs to be imported:\n\n```csharp\nusing Optional.Unsafe;\n```\n\nWhen imported, values can be retrieved unsafely as:\n\n```csharp\nvar value = option.ValueOrFailure();\nvar anotherValue = option.ValueOrFailure(\"An error message\"); \n```\n\nIn case of failure an `OptionValueMissingException` is thrown.\n\nIn a lot of interop scenarios, it might be necessary to convert an option into a potentially null value. Once the Unsafe namespace is imported, this can be done relatively concisely as:\n\n```csharp\nvar value = option.ValueOrDefault(); // value will be default(T) if the option is empty.\n```\n\nSimilarly, it is possible to convert an option into to a nullable (insofar as the inner value is a value type):\n\n\n```csharp\nvar nullable = option.ToNullable();\n```\n\nAs a rule of thumb, such conversions should be performed only just before the nullable value is needed (e.g. passed to an external library), to minimize and localize the potential for null reference exceptions and the like. \n\n### Transforming and filtering values\n\nA few extension methods are provided to safely manipulate optional values.\n\nThe `Or` function makes it possible to specify an alternative value. If the option is none, a some instance will be returned:\n\n```csharp\nvar none = Option.None\u003cint\u003e();\nvar some = none.Or(10); // A some instance, with value 10\nvar some = none.Or(() =\u003e SlowOperation()); // Lazy variant\n```\n\nSimilarly, the `Else` function enables you to specify an alternative option, which will replace the current one, in case no value is present. Notice, that both options might be none, in which case a none-option will be returned:\n\n```csharp\nvar none = Option.None\u003cint\u003e();\nvar some = none.Else(10.Some()); // A some instance, with value 10\nvar some = none.Else(Option.None\u003cint\u003e()); // A none instance\nvar some = none.Else(() =\u003e Option.Some\u003cint\u003e()); // Lazy variant\n```\n\nThe `Map` function transforms the inner value of an option. If no value is present none is simply propagated:\n\n```csharp\nvar none = Option.None\u003cint\u003e();\nvar stillNone = none.Map(x =\u003e x + 10);\n\nvar some = 10.Some();\nvar somePlus10 = some.Map(x =\u003e x + 10);\n```\n\nThe `FlatMap` function chains several optional values. It is similar to `Map`, but the return type of the transformation must be another optional. If either the resulting or original optional value is none, a none instance is returned. Otherwise, a some instance is returned according to the specified transformation:\n\n```csharp\nvar none = Option.None\u003cint\u003e();\nvar stillNone = none.FlatMap(x =\u003e x.Some()); // Returns another Option\u003cint\u003e\n\nvar some = 10.Some();\nvar stillSome = some.FlatMap(x =\u003e x.Some()); \nvar none = some.FlatMap(x =\u003e x.None()); // Turns empty, as it maps to none\n```\n\n`FlatMap` is useful in combination with methods that return optional values themselves:\n\n```csharp\npublic static Option\u003cPerson\u003e FindPersonById(int id) { ... }\npublic static Option\u003cHairstyle\u003e GetHairstyle(Person person) { ... }\n\nvar id = 10;\nvar person = FindPersonById(id);\nvar hairstyle = person.FlatMap(p =\u003e GetHairstyle(p));\nhairstyle.Match( ... );\n```\n\nIn case you end up with a nested optional (e.g. `Option\u003cOption\u003cT\u003e\u003e`), you might flatten it by flatmapping it onto itself, but a dedicated `Flatten` function is offered for convenience:\n\n```csharp\nOption\u003cOption\u003cT\u003e\u003e nestedOption = ...\nOption\u003cT\u003e option = nestedOption.Flatten(); // same as nestedOption.FlatMap(o =\u003e o)\n```\n\nFinally, it is possible to perform filtering. The `Filter` function returns none, if the specified predicate is not satisfied. If the option is already none, it is simply returned as is:\n\n```csharp\nvar none = Option.None\u003cint\u003e();\nvar stillNone = none.Filter(x =\u003e x \u003e 10);\n\nvar some = 10.Some();\nvar stillSome = some.Filter(x =\u003e x == 10);\nvar none = some.Filter(x =\u003e x != 10);\n```\n\nA recurring scenario, when working with null-returning APIs, is that of filtering away null values after a mapping. To ease the pain, a specific `NotNull` filter is provided:\n\n```csharp\n// Returns none if the parent node is null\nvar parent = GetNode()\n    .Map(node =\u003e node.Parent)\n    .NotNull(); \n```\n\n### Enumerating options\n\nAn option implements `GetEnumerator`, allowing you to loop over the value, as if it was a collection with either a single or no elements.\n\n```csharp\nforeach (var value in option)\n{\n    Console.WriteLine(value);\n}\n```\n\nAs you might have noticed, this is a nice and lightweight alternative to `Match` in cases where you only want to do something if the value is present. Also, you should use this instead of the more verbose and unsafe combination of `option.HasValue` and `option.ValueOrFailure()`, which you might otherwise be tempted to try.\n\nNotice, however, that options don't actually implement `IEnumerable\u003cT\u003e`, in order to not pollute the options with LINQ extension methods and the like. Although many LINQ methods share functionality similar to those offered by an option, they offer a more collection-oriented interface, and includes several unsafe functions (such as `First`, `Single`, etc).\n\nAlthough options deliberately don't act as enumerables, you can easily convert an option to an enumerable by calling the `ToEnumerable()` method:\n\n```csharp\nvar enumerable = option.ToEnumerable();\n```\n\n### Working with LINQ query syntax\n\nOptional supports LINQ query syntax, to make the above transformations somewhat cleaner.\n\nTo use LINQ query syntax you must import the following namespace:\n\n```csharp\nusing Optional.Linq;\n```\n\nThis allows you to do fancy stuff such as:\n\n```csharp\nvar personWithGreenHair =\n  from person in FindPersonById(10)\n  from hairstyle in GetHairstyle(person)\n  from color in ParseStringToColor(\"green\")\n  where hairstyle.Color == color\n  select person;\n```\n\nIn general, this closely resembles a sequence of calls to `FlatMap` and `Filter`. However, using query syntax can be a lot easier to read in complex cases.\n\n### Equivalence and comparison\n\nTwo optional values are equal if the following is satisfied:\n\n* The two options have the same type\n* Both are none, both contain null values, or the contained values are equal\n\nAn option both overrides `object.Equals` and implements `IEquatable\u003cT\u003e`, allowing efficient use in both generic and untyped scenarios. The `==` and `!=` operators are also provided for convenience. In each case, the semantics are identical.\n\nThe generated hashcodes also reflect the semantics described above.\n\nFurther, options implement `IComparable\u003cT\u003e` and overload the corresponding comparison operators (`\u003c \u003e \u003c= \u003e=`). The implementation is consistent with the above described equality semantics, and comparison itself is based on the following rules:\n\n* An empty option is considered less than a non-empty option\n* For non-empty options comparison is delegated to the default comparer and applied on the contained value\n\n### Options with exceptional values\n\nAs described above, Optional support the notion of an either type, which adds and exception value, indicating how an operation went wrong.\n\nAn `Option\u003cT, TException\u003e` can be created directly, just like the `Option\u003cT\u003e`. Unlike in this simple case, we need to specify potential exceptional values (and a lot of verbose type annotations - sorry guys):\n\n```csharp\nvar none = Option.None\u003cint, ErrorCode\u003e(ErrorCode.GeneralError);\nvar some = Option.Some\u003cint, ErrorCode\u003e(10);\n\n// These extension methods are hardly useful in this case,\n// but here for consistency\nvar none = 10.None(ErrorCode.GeneralError);\nvar some = 10.Some\u003cint, ErrorCode\u003e();\n\nstring str = \"abc\";\nvar none = str.SomeWhen(s =\u003e s == \"cba\", ErrorCode.GeneralError);\nvar none = str.SomeWhen(s =\u003e s == \"cba\", () =\u003e SlowOperation()); // Lazy variant\n\nstring nullString = null;\nvar none = nullString.SomeNotNull(ErrorCode.GeneralError); \nvar none = nullString.SomeNotNull(() =\u003e SlowOperation()); // Lazy variant\n\nint? nullableWithoutValue = null;\nint? nullableWithValue = 2;\nvar none = nullableWithoutValue.ToOption(ErrorCode.GeneralError);\nvar some = nullableWithValue.ToOption(ErrorCode.GeneralError);\nvar some = nullableWithValue.ToOption(() =\u003e SlowOperation()); // Lazy variant\n```\n\nRetrieval of values is very similar as well:\n\n```csharp\nvar hasValue = option.HasValue;\nvar isThousand = option.Contains(1000);\nvar isGreaterThanThousand = option.Exists(val =\u003e val \u003e 1000);\n\nvar value = option.ValueOr(10);\nvar value = option.ValueOr(() =\u003e SlowOperation()); // Lazy variant\nvar value = option.ValueOr(exception =\u003e (int)exception); // Mapped from exceptional value\n\n// If the value and exception is of identical type, \n// it is possible to return the one which is present\nvar value = option.ValueOrException(); \n```\n\nThe `Match` methods include the exceptional value in the none-case:\n\n```csharp\nvar value = option.Match(\n  some: value =\u003e value + 1, \n  none: exception =\u003e (int)exception\n);\n\noption.Match(\n  some: value =\u003e Console.WriteLine(value), \n  none: exception =\u003e Console.WriteLine(exception)\n);\n\noption.MatchSome(value =\u003e Console.WriteLine(value));\noption.MatchNone(exception =\u003e Console.WriteLine(exception));\n```\n\nAnd again, when `Optional.Unsafe` is imported, it is possible to retrieve the value without safety:\n\n```csharp\nvar value = option.ValueOrFailure();\nvar anotherValue = option.ValueOrFailure(\"An error message\"); \nvar potentiallyNullValue = option.ValueOrDefault();\n```\n\nValues can be conveniently transformed using similar operations to that of the `Option\u003cT\u003e`. It is however important to note, that these transformations are all **short-circuiting**! That is, if an option is already none, the current exceptional value will remain, and not be replaced by any subsequent filtering. In this respect, this exceptional value is very similar to actual exceptions (hence the name).\n\n```csharp\nvar none = Option.None\u003cint, ErrorCode\u003e(ErrorCode.GeneralError);\nvar some = none.Or(10);\nvar some = none.Or(() =\u003e SlowOperation()); // Lazy variant\nvar some = none.Or(exception = (int)exception); // Mapped from exceptional value\nvar some = none.Else(10.Some\u003cint, ErrorCode\u003e()); // A some instance with value 10\nvar some = none.Else(Option.None\u003cint, ErrorCode\u003e(ErrorCode.FatalError)); // A none instance carrying a ErrorCode.FatalError\nvar some = none.Else(() =\u003e 10.Some\u003cint, ErrorCode\u003e()); // Lazy variant\nvar some = none.Else(exception = Option.None\u003cint, ErrorCode\u003e(exception)); // Mapped from exceptional value\n\n// Mapping\n\nvar none = Option.None\u003cint, ErrorCode\u003e(ErrorCode.GeneralError);\nvar stillNone = none.Map(x =\u003e x + 10);\n\nvar some = Option.Some\u003cint, ErrorCode\u003e(10);\nvar somePlus10 = some.Map(x =\u003e x + 10);\n\n// Flatmapping\n\nvar none = Option.None\u003cint, ErrorCode\u003e(ErrorCode.GeneralError);\nvar stillNone = none.FlatMap(x =\u003e x.Some\u003cint, ErrorCode\u003e());\n\nvar some = Option.Some\u003cint, ErrorCode\u003e(10);\nvar stillSome = some.FlatMap(x =\u003e x.Some\u003cint, ErrorCode\u003e()); \nvar none = some.FlatMap(x =\u003e x.None(ErrorCode.GeneralError));\n\nOption\u003cOption\u003cint, ErrorCode\u003e, ErrorCode\u003e nestedOption = ...\nOption\u003cint, ErrorCode\u003e option = nestedOption.Flatten();\n\n// Filtering\n\nvar result = Option.Some\u003cint, ErrorCode\u003e(10)\n    .Filter(x =\u003e true, ErrorCode.GeneralError) // Stil some\n    .Filter(x =\u003e false, ErrorCode.GeneralError) // Now \"GeneralError\"\n    .Filter(x =\u003e false, ErrorCode.IncorrectValue) // Still \"GeneralError\"\n    .Filter(x =\u003e false, () =\u003e SlowOperation()); // Lazy variant\n\nvar result = Option.Some\u003cstring, ErrorCode\u003e(null)\n    .NotNull(ErrorCode.GeneralError) // Returns none if the contained value is null\n    .NotNull(() =\u003e SlowOperation()); // Lazy variant\n```\n\nEnumeration works identically to that of `Option\u003cT\u003e`:\n\n```csharp\nforeach (var value in option)\n{\n    // Do something\n}\n\nvar enumerable = option.ToEnumerable();\n```\n\nLINQ query syntax is supported, with the notable exception of the `where` operator (as it doesn't allow us to specify an exceptional value to use in case of failure):\n\n```csharp\nvar optionalDocument =\n  from file in user.GetFileFromDatabase()\n  from document in FetchFromService(file.DocumentId)\n  select document;\n\noptionalDocument.Match(\n    some: document =\u003e Console.WriteLine(document.Contents), \n    none: errorCode =\u003e Console.WriteLine(errorCode)\n);\n```\n\n### Interop between `Option\u003cT\u003e` and `Option\u003cT, TException\u003e`\n\nTo make interop between `Option\u003cT\u003e` and `Option\u003cT, TException\u003e` more convenient, several utility methods are provided for this purpose.\n\nThe most basic of such operations, is to simply convert between the two types:\n\n```csharp\nvar some = Option.Some(\"This is a string\");\n\n// To convert to an Option\u003cT, TException\u003e, we need to tell which \n// exceptional value to use if the current option is none\nvar someWithException = some.WithException(ErrorCode.GeneralError);\nvar someWithException = some.WithException(() =\u003e SlowOperation()); // Lazy variant\n\n// It is easy to simply drop the exceptional value\nvar someWithoutException = someWithException.WithoutException();\n```\n\nWhen flatmapping, it is similarly possible to flatmap into a value of the other type:\n\n```csharp\n// The following flatmap simply ignores the new exceptional value\nvar some = Option.Some(\"This is a string\");\nvar none = some.FlatMap(x =\u003e x.None(ErrorCode.GeneralError));\n\n// The following flatmap needs an explicit exceptional value \n// as a second argument\nvar some = Option.Some\u003cstring, ErrorCode\u003e(\"This is a string\");\nvar none = some.FlatMap(x =\u003e Option.None\u003cstring\u003e(), ErrorCode.GeneralError);\nvar none = some.FlatMap(x =\u003e Option.None\u003cstring\u003e(), () =\u003e SlowOperation()); // Lazy variant\n```\n\n### Working with collections\n\nOptional provides a few convenience methods to ease interoperability with common .NET collections, and improve null safety a bit in the process.\n\nLINQ provides a lot of useful methods when working with enumerables, but methods such as `FirstOrDefault`, `LastOrDefault`, `SingleOrDefault`, and `ElementAtOrDefault`, all return null (more precisely `default(T)`) to indicate that no value was found (e.g. if the enumerable was empty). Optional provides a safer alternative to all these methods, returning an option to indicate success/failure instead of nulls. As an added benefit, these methods work unambiguously for non-nullable/structs types as well, unlike their LINQ counterparts. \n\n```csharp\nvar option = values.FirstOrNone();\nvar option = values.FirstOrNone(v =\u003e v != 0);\nvar option = values.LastOrNone();\nvar option = values.LastOrNone(v =\u003e v != 0);\nvar option = values.SingleOrNone();\nvar option = values.SingleOrNone(v =\u003e v != 0);\nvar option = values.ElementAtOrNone(10);\n```\n\n(Note that unlike `SingleOrDefault`, `SingleOrNone` never throws an exception but returns None in all \"invalid\" cases. This slight deviation in semantics was considered a safer alternative to the existing behavior, and is easy to work around in practice, if the finer granularity is needed.)\n\nOptional provides a safe way to retrieve values from a dictionary:\n\n```csharp\nvar option = dictionary.GetValueOrNone(\"key\");\n```\n\n`GetValueOrNone` behaves similarly to `TryGetValue` on an `IDictionary\u003cTKey, TValue\u003e` or `IReadOnlyDictionary\u003cTKey, TValue\u003e`, but actually supports any `IEnumerable\u003cKeyValuePair\u003cTKey, TValue\u003e\u003e` (falling back to iteration, when a direct lookup is not possible).\n\nAnother common scenario, is to perform various transformations on an enumerable and ending up with a sequence of options (e.g. `IEnumerable\u003cOption\u003cT\u003e\u003e`). In many cases, only the non-empty options are relevant, and as such Optional provides a convenient method to flatten a sequence of options into a sequence containing all the inner values (whereas empty options are simply thrown away):\n\n```csharp\nvar options = new List\u003cOption\u003cint\u003e\u003e { Option.Some(1), Option.Some(2), Option.None\u003cint\u003e() };\nvar values = option.Values(); // IEnumerable\u003cint\u003e { 1, 2 }\n```\n\nWhen working with a sequence of `Option\u003cT, TException\u003e` a similar method is provided, as well a way to extract all the exceptional values:\n\n```csharp\nvar options = GetOptions(); // IEnumerable\u003cOption\u003cint, string\u003e\u003e { Some(1), None(\"error\"), Some(2) }\nvar values = options.Values(); // IEnumerable\u003cint\u003e { 1, 2 }\nvar exceptions = options.Exceptions(); // IEnumerable\u003cstring\u003e { \"error\" }\n```\n","funding_links":[],"categories":["Frameworks, Libraries and Tools","Functional programming","函数式编程","C# #","others","框架, 库和工具"],"sub_categories":["Functional Programming","响应式编程"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnlkl%2FOptional","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnlkl%2FOptional","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnlkl%2FOptional/lists"}