RustlikeValues.Option 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package RustlikeValues.Option --version 1.0.0
                    
NuGet\Install-Package RustlikeValues.Option -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RustlikeValues.Option" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RustlikeValues.Option" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="RustlikeValues.Option" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RustlikeValues.Option --version 1.0.0
                    
#r "nuget: RustlikeValues.Option, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RustlikeValues.Option@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RustlikeValues.Option&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=RustlikeValues.Option&version=1.0.0
                    
Install as a Cake Tool

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.

🚀 Quick Start

using RustlikeValues.RustlikeOption;

// Creating Options
var some = Option.Some(42);
var none = Option.None<int>();

// 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

📚 Core API

Creation

// Create Some variant
var some = Option.Some("Hello");
var someInt = Option.Some(42);

// Create None variant
var none = Option.None<string>();

// Safe creation from potentially throwing code
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");
}

// Implicit conversion to bool
if (option) // true if Some, false if None
{
    Console.WriteLine("Has value!");
}

Getting Values

var option = Option.Some(42);

// Get value or throw exception
var value = option.Unwrap(); // 42

// Get value or use default
var value = option.UnwrapOr(0); // 42

// Get value or compute from function
var value = option.UnwrapOrElse(() => DateTime.Now.Millisecond);

// Get value or null/default(T) - may return null!
var value = option.GetValueOrDefault(); // 42 or null/default

// Safe alternative to Unwrap (returns the option itself)
var safeOption = option.TryUnwrap(); // returns the option, never throws

Transformations

var option = Option.Some("hello");

// Map: transform the value if present
var upper = option.Map(s => s.ToUpper()); // Some("HELLO")

// Filter: keep value only if predicate is true
var filtered = option.Filter(s => s.Length > 3); // Some("hello")

// AndThen: chain operations that return Options
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");

// Async map
var response = await option.MapAsync(async url => 
    await httpClient.GetStringAsync(url));

// Async AndThen
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);

// Zip two options together
var person = name.Zip(age); // Some(("John", 30))

// Use one option or another
var option1 = Option.None<string>();
var option2 = Option.Some("fallback");
var result = option1.Or(option2); // Some("fallback")

// Compute alternative if None
var result = option1.OrElse(() => Option.Some("computed"));

🎭 Pattern Matching

var option = Option.Some(42);

// Match with return value
var result = option.Match(
    Some: value => $"Got {value}",
    None: () => "No value"
);

// Match with side effects
option.Match(
    Some: value => Console.WriteLine($"Value: {value}"),
    None: () => Console.WriteLine("No value")
);

// Deconstruction
var (isSome, value) = option;
if (isSome)
{
    Console.WriteLine($"Value: {value}");
}

🔧 LINQ Integration

using RustlikeValues.RustlikeOption;

// Option implements IEnumerable<T>
var numbers = new[] 
{
    Option.Some(1),
    Option.None<int>(),
    Option.Some(3)
};

var sum = numbers
    .SelectMany(opt => opt) // Flatten Some values
    .Sum(); // 4

// Use with LINQ Where, Select, etc.
var result = Option.Some(42)
    .Where(x => x > 0)
    .Select(x => x * 2); // Some(84)

📄 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);
// {"Name":"John","Email":"john@example.com","Age":null}

var deserialized = JsonSerializer.Deserialize<User>(json);
// Email = Some("john@example.com"), Age = None

🔄 Implicit Conversions

// Implicit conversion from T to Option<T>
Option<string> option = "hello"; // Some("hello")

// Implicit conversion to bool
if (option) // true if Some
{
    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 };

// Old way - prone to exceptions
// var value = dict["key"]; // KeyNotFoundException if missing

// New way - safe
var option = dict.ContainsKey("key") 
    ? Option.Some(dict["key"]) 
    : Option.None<int>();

var result = option.UnwrapOr(0);

Safe Parsing

// Safe integer parsing
var input = "123";
var number = Option.TryCreate(() => int.Parse(input))
    .Filter(x => x > 0)
    .Map(x => x * 2)
    .UnwrapOr(0);

Chaining Operations

public Option<User> GetUser(int id) => /* ... */;
public Option<Profile> GetProfile(User user) => /* ... */;
public Option<string> GetAvatarUrl(Profile profile) => /* ... */;

// Chain operations safely
var avatarUrl = GetUser(userId)
    .AndThen(GetProfile)
    .AndThen(GetAvatarUrl)
    .UnwrapOr("/default-avatar.png");
  • RustlikeValues.Result - For error handling with Result<T, E>
  • RustlikeValues.Extensions - Additional utility methods
  • RustlikeValues - Meta-package containing all types

🤝 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • 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.

Version Downloads Last Updated
2.0.2 142 6/24/2025
2.0.1 79 6/20/2025
2.0.0 146 6/19/2025
1.0.1 146 6/18/2025
1.0.0 146 6/18/2025