RustlikeValues.Option 1.0.1

There is a newer version of this package available.
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
                    
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.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RustlikeValues.Option" Version="1.0.1" />
                    
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.1
                    
#r "nuget: RustlikeValues.Option, 1.0.1"
                    
#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.1
                    
#: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.1
                    
Install as a Cake Addin
#tool nuget:?package=RustlikeValues.Option&version=1.0.1
                    
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.

Creating None values:

  • Option.None<T>() - Explicit method (recommended)
  • default(Option<T>) - Using default keyword
  • default - 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>();
  • 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 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 141 6/24/2025
2.0.1 78 6/20/2025
2.0.0 145 6/19/2025
1.0.1 145 6/18/2025
1.0.0 145 6/18/2025