NCode.PropertyBag
1.2.0
Prefix Reserved
dotnet add package NCode.PropertyBag --version 1.2.0
NuGet\Install-Package NCode.PropertyBag -Version 1.2.0
<PackageReference Include="NCode.PropertyBag" Version="1.2.0" />
<PackageVersion Include="NCode.PropertyBag" Version="1.2.0" />
<PackageReference Include="NCode.PropertyBag" />
paket add NCode.PropertyBag --version 1.2.0
#r "nuget: NCode.PropertyBag, 1.2.0"
#:package NCode.PropertyBag@1.2.0
#addin nuget:?package=NCode.PropertyBag&version=1.2.0
#tool nuget:?package=NCode.PropertyBag&version=1.2.0
NCode.PropertyBag
A lightweight, strongly-typed property bag library for .NET that provides type-safe key-value storage with support for scoped values, cloning, and dependency injection.
Features
- Strongly-Typed Keys - Type-safe
PropertyBagKey<T>ensures compile-time type checking when storing and retrieving values - Nullable Value Support - Explicitly store and retrieve
nullvalues for reference types and nullable value types - Read-Only Interface -
IReadOnlyPropertyBagfor passing property bags to code that should only read values - Fluent API - Method chaining support for
SetandRemoveoperations - Scoped Values - Temporarily override values with automatic cleanup using
IPropertyBagScope - Cloning Support - Create independent copies with
Clone(), supporting deep cloning forICloneablevalues - Lazy Initialization - Empty property bags are lightweight with no memory allocated until first use
- Dictionary Access -
DefaultPropertyBagimplementsIReadOnlyDictionary<PropertyBagKey, object?>for enumeration - Dependency Injection - Built-in integration with
Microsoft.Extensions.DependencyInjection - Convenience Extensions - Automatic key name inference using
CallerArgumentExpression
Installation
dotnet add package NCode.PropertyBag
Or for abstractions only:
dotnet add package NCode.PropertyBag.Abstractions
Quick Start
Basic Usage
// Define keys (typically as static readonly fields)
public static readonly PropertyBagKey<string> UserNameKey = new("UserName");
public static readonly PropertyBagKey<int> UserAgeKey = new("UserAge");
// Create and use a property bag
var propertyBag = PropertyBagFactory.Create();
propertyBag
.Set(UserNameKey, "Alice")
.Set(UserAgeKey, 30);
if (propertyBag.TryGetValue(UserNameKey, out var userName))
{
Console.WriteLine($"User: {userName}"); // Output: User: Alice
}
Scoped Values
Temporarily override a value that automatically restores when disposed:
var cultureKey = new PropertyBagKey<string>("Culture");
propertyBag.Set(cultureKey, "en-US");
using (propertyBag.Scope(cultureKey, "fr-FR"))
{
// Within this scope, Culture is "fr-FR"
propertyBag.TryGetValue(cultureKey, out var culture); // "fr-FR"
}
// After disposal, Culture is restored to "en-US"
propertyBag.TryGetValue(cultureKey, out var restored); // "en-US"
Dependency Injection
Register services with the DI container:
services.AddPropertyBag();
Then inject IPropertyBagFactory where needed:
public class MyService
{
private readonly IPropertyBagFactory _factory;
public MyService(IPropertyBagFactory factory)
{
_factory = factory;
}
public IPropertyBag CreateContext() => _factory.Create();
}
Convenience Extensions
Use automatic key name inference:
var connectionString = "Server=localhost;Database=test";
var timeout = TimeSpan.FromSeconds(30);
// Keys are inferred as "connectionString" and "timeout"
propertyBag
.Set(connectionString)
.Set(timeout);
// Retrieve with inferred key name
// Note: declare variable first - inline declaration (out string? x) won't infer the key name correctly
string? connectionString;
if (propertyBag.TryGet(out connectionString)) // Key inferred as "connectionString"
{
Console.WriteLine(connectionString);
}
Nullable Values
Null values can be explicitly stored and retrieved:
var optionalNameKey = new PropertyBagKey<string?>("OptionalName");
// Explicitly store null
propertyBag.Set(optionalNameKey, null);
// TryGetValue returns true because the key exists (even though value is null)
if (propertyBag.TryGetValue(optionalNameKey, out var name))
{
// name is null here, but the key was found
Console.WriteLine(name ?? "(not set)");
}
// This is different from a missing key
var missingKey = new PropertyBagKey<string?>("Missing");
if (!propertyBag.TryGetValue(missingKey, out _))
{
// Key does not exist
}
API Overview
Abstractions (NCode.PropertyBag.Abstractions)
| Type | Description |
|---|---|
PropertyBagKey |
Non-generic key with Type and Name properties |
PropertyBagKey<T> |
Strongly-typed key for type-safe value access |
IReadOnlyPropertyBag |
Read-only interface with TryGetValue and Clone |
IPropertyBag |
Mutable interface adding Set, Remove, and Scope |
IPropertyBagScope |
Disposable scope for temporary value overrides |
IPropertyBagFactory |
Factory interface for creating property bags |
PropertyBagExtensions |
Convenience methods with automatic key inference |
Implementation (NCode.PropertyBag)
| Type | Description |
|---|---|
DefaultPropertyBag |
Dictionary-based implementation with lazy initialization |
DefaultPropertyBagFactory |
Default factory with singleton support |
DefaultPropertyBagScope |
Scope implementation that removes values on dispose |
PropertyBagFactory |
Static convenience class for creating property bags |
DefaultRegistration |
DI registration extension methods |
License
Licensed under the Apache License, Version 2.0. See LICENSE.txt for details.
Target Frameworks
- .NET 8.0
- .NET 10.0
Release Notes
- v1.0.0 - Initial release
- v1.0.1 - Fix CI build
- v1.1.0 - Added NET 8.0 build
- v1.1.1 - Fixed TryGet documentation example to show correct variable declaration pattern
- v1.2.0 - Added explicit support for nullable values;
TryGetValuenow returnstruewhen a key exists with anullvalue
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. 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 is compatible. 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. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2)
- NCode.PropertyBag.Abstractions (>= 1.2.0)
-
net8.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2)
- NCode.PropertyBag.Abstractions (>= 1.2.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Built on 2026-01-19 18:51:53Z