RustlikeValues.Option
1.0.1
See the version list below for details.
dotnet add package RustlikeValues.Option --version 1.0.1
NuGet\Install-Package RustlikeValues.Option -Version 1.0.1
<PackageReference Include="RustlikeValues.Option" Version="1.0.1" />
<PackageVersion Include="RustlikeValues.Option" Version="1.0.1" />
<PackageReference Include="RustlikeValues.Option" />
paket add RustlikeValues.Option --version 1.0.1
#r "nuget: RustlikeValues.Option, 1.0.1"
#:package RustlikeValues.Option@1.0.1
#addin nuget:?package=RustlikeValues.Option&version=1.0.1
#tool nuget:?package=RustlikeValues.Option&version=1.0.1
RustlikeValues.Option
A Rust-inspired Option<T>
type for C# that provides safe nullable value handling and eliminates null reference exceptions.
📦 Installation
dotnet add package RustlikeValues.Option
🎯 What is Option<T>?
The Option<T>
type represents an optional value: every Option
is either:
- Some - contains a value of type
T
- None - contains no value
This eliminates null reference exceptions and makes nullable handling explicit and safe.
Creating None values:
Option.None<T>()
- Explicit method (recommended)default(Option<T>)
- Using default keyworddefault
- In assignment contexts where type is inferred
Note: default
works reliably when the generic type T
can be inferred from context, especially when used alongside Some
values in the same scope.
🚀 Quick Start
using RustlikeValues.RustlikeOption;
// Creating Options
var some = Option.Some(42);
var none1 = Option.None<int>(); // Explicit None
var none2 = default(Option<int>); // Using default
// Safe transformations
var result = some
.Map(x => x * 2) // Transform the value if present
.Filter(x => x > 50) // Keep only if condition is true
.UnwrapOr(0); // Get value or default
// result = 84
// Note: default works best in contexts where type is clear
// and you're mixing with Some values
📚 Core API
Creation
var some = Option.Some("Hello");
var someInt = Option.Some(42);
var none1 = Option.None<string>();
Option<string> none2 = default;
var conditional = someCondition
? Option.Some("value")
: default;
Option<string> conditional2 = someCondition
? Option.Some("value")
: default;
var option = Option.TryCreate(() => int.Parse("123"));
Checking State
var option = Option.Some(42);
if (option.IsSome)
{
Console.WriteLine("Has value!");
}
if (option.IsNone)
{
Console.WriteLine("No value");
}
if (option)
{
Console.WriteLine("Has value!");
}
Getting Values
var option = Option.Some(42);
var value = option.Unwrap();
var value = option.UnwrapOr(0);
var value = option.UnwrapOrElse(() => DateTime.Now.Millisecond);
var value = option.GetValueOrDefault();
var safeOption = option.TryUnwrap();
Transformations
var option = Option.Some("hello");
var upper = option.Map(s => s.ToUpper());
var filtered = option.Filter(s => s.Length > 3);
var result = option.AndThen(s =>
s.Length > 0 ? Option.Some(s.Length) : Option.None<int>());
Async Operations
var option = Option.Some("https://api.example.com");
var response = await option.MapAsync(async url =>
await httpClient.GetStringAsync(url));
var parsed = await option.AndThenAsync(async url =>
{
var json = await httpClient.GetStringAsync(url);
return TryParseJson(json);
});
Combining Options
var name = Option.Some("John");
var age = Option.Some(30);
var person = name.Zip(age);
var option1 = Option.None<string>();
var option2 = Option.Some("fallback");
var result = option1.Or(option2);
var result = option1.OrElse(() => Option.Some("computed"));
🎭 Pattern Matching
var option = Option.Some(42);
var result = option.Match(
Some: value => $"Got {value}",
None: () => "No value"
);
option.Match(
Some: value => Console.WriteLine($"Value: {value}"),
None: () => Console.WriteLine("No value")
);
var (isSome, value) = option;
if (isSome)
{
Console.WriteLine($"Value: {value}");
}
🔧 LINQ Integration
using RustlikeValues.RustlikeOption;
var numbers = new[]
{
Option.Some(1),
Option.None<int>(),
Option.Some(3)
};
var sum = numbers
.SelectMany(opt => opt)
.Sum();
var result = Option.Some(42)
.Where(x => x > 0)
.Select(x => x * 2);
var options = new[]
{
Option.Some("hello"),
default(Option<string>),
Option.Some("world")
};
📄 JSON Serialization
Options serialize naturally with System.Text.Json:
public class User
{
public string Name { get; set; }
public Option<string> Email { get; set; }
public Option<int> Age { get; set; }
}
var user = new User
{
Name = "John",
Email = Option.Some("john@example.com"),
Age = Option.None<int>()
};
var json = JsonSerializer.Serialize(user);
var deserialized = JsonSerializer.Deserialize<User>(json);
🔄 Implicit Conversions
Option<string> option = "hello";
if (option)
{
Console.WriteLine("Has value");
}
🏃♂️ Performance
- Zero allocation for None values (static readonly)
- Minimal overhead for Some values (single allocation)
- Aggressive inlining for hot path methods
- Struct-based design for stack allocation
📖 Examples
Safe Dictionary Access
var dict = new Dictionary<string, int> { ["key"] = 42 };
var option = dict.ContainsKey("key")
? Option.Some(dict["key"])
: default;
var result = option.UnwrapOr(0);
var noneExample = Option.None<int>();
Safe Parsing
public Option<int> ParseInt(string input)
{
return int.TryParse(input, out var value)
? Option.Some(value)
: default;
}
var number = ParseInt("123")
.Filter(x => x > 0)
.Map(x => x * 2)
.UnwrapOr(0);
var invalidParse = Option.None<int>();
Chaining Operations
public Option<User> GetUser(int id) => /* ... */;
public Option<Profile> GetProfile(User user) => /* ... */;
public Option<string> GetAvatarUrl(Profile profile) => /* ... */;
var avatarUrl = GetUser(userId)
.AndThen(GetProfile)
.AndThen(GetAvatarUrl)
.UnwrapOr("/default-avatar.png");
public Option<T> FindById<T>(int id, List<T> items) where T : IHasId
{
return id > 0 && items.Any(x => x.Id == id)
? Option.Some(items.First(x => x.Id == id))
: default;
}
var emptyResult = Option.None<User>();
🔗 Related Packages
- RustlikeValues.Result - For error handling with Result<T, E>
- RustlikeValues.Extensions - Additional utility methods
🤝 Contributing
Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.
📄 License
This project is licensed under the MIT License.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.