A high-performance memoization library for .NET that helps create cached functions with automatic result caching. Supports multiple cache implementations and provides efficient memory management for function result caching and performance optimization.
Deps
6
Install Size
—
Vulns
✓ 0
Published
Aug 22, 2025
$ dotnet add package Memoization.NetA high-performance memoization library for .NET that provides automatic function result caching to improve performance by avoiding redundant computations.
Memoization is an optimization technique that stores the results of expensive function calls and returns the cached result when the same inputs occur again. This library provides a simple and efficient way to memoize functions in C# using Microsoft's IMemoryCache.
Microsoft.Extensions.Caching.Abstractions for optimal performanceMemoryCacheEntryOptions (TTL, size limits, etc.)IMemoryCache implementationsdotnet add package Memoization.Net
using Microsoft.Extensions.Caching.Memory;
using Memoization;
// Set up the default cache (typically done once at application startup)
Memoization.DefaultCache = new MemoryCache(new MemoryCacheOptions
{
SizeLimit = 1000,
CompactionPercentage = 0.25
});
// Example: Expensive recursive function
static int Fibonacci(int n)
{
Console.WriteLine($"Computing Fibonacci({n})");
return n < 2 ? 1 : Fibonacci(n - 1) + Fibonacci(n - 2);
}
// Create memoized version
var memoizedFib = Memoization.Create<int, int>(Fibonacci);
// First call - computes and caches result
var result1 = memoizedFib(10); // Prints computation messages
// Second call - returns cached result instantly
var result2 = memoizedFib(10); // No computation, returns cached result
// Use a specific cache instance
var customCache = new MemoryCache(new MemoryCacheOptions());
var memoizedFunc = Memoization.Create(expensiveFunction, customCache);
// Configure cache entry options
var options = new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30),
SlidingExpiration = TimeSpan.FromMinutes(5),
Priority = CacheItemPriority.High
};
var memoizedFunc = Memoization.Create(expensiveFunction, options);
// Function with multiple parameters
static double ExpensiveCalculation(double x, double y, int iterations)
{
// Simulate expensive computation
return Math.Pow(x + y, iterations % 10);
}
var memoized = Memoization.Create<double, double, int, double>(ExpensiveCalculation);
var result = memoized(3.14, 2.71, 1000);
The library uses tuples of input parameters as cache keys. For best performance:
GetHashCode() and Equals() methods// Configure cache with size limits to prevent memory issues
var options = new MemoryCacheOptions
{
SizeLimit = 1000,
CompactionPercentage = 0.20
};
var cache = new MemoryCache(options);
Failed function calls do not pollute the cache:
var memoized = Memoization.Create<int, string>(x =>
{
if (x < 0) throw new ArgumentException("Negative input");
return x.ToString();
});
try { memoized(-1); } catch { /* Exception thrown, nothing cached */ }
var result = memoized(5); // Will compute and cache successfully
All memoization operations depend on the thread safety of the underlying IMemoryCache implementation. Since this library uses Microsoft.Extensions.Caching.Abstractions, the thread safety depends on the specific IMemoryCache implementation being used. The default Microsoft.Extensions.Caching.Memory implementation is thread-safe, so multiple threads can safely call memoized functions concurrently:
var memoized = Memoization.Create(expensiveFunction);
// Safe to call from multiple threads (with thread-safe IMemoryCache implementation)
Parallel.For(0, 100, i =>
{
var result = memoized(i % 10); // Concurrent access is safe
});
Note: While cache operations are typically thread-safe, the memoized function itself should be thread-safe (or pure) to avoid issues with concurrent execution. Additionally, when the same inputs are being processed concurrently by multiple threads, the expensive function may be executed multiple times before the result is cached.
DefaultCache once during application startup// Cache expensive database queries
var cachedQuery = Memoization.Create<int, User>(userId =>
{
return database.Users.FirstOrDefault(u => u.Id == userId);
}, new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
});
// Cache complex mathematical computations
var cachedCompute = Memoization.Create<double[], double>(weights =>
{
return weights.Select((w, i) => w * Math.Pow(i, 2)).Sum();
});
LGPL-3.0-or-later WITH LGPL-3.0-linking-exception. See LICENSE for details.