Skip to content

Latest commit

 

History

History
133 lines (111 loc) · 3.64 KB

weak-reference.md

File metadata and controls

133 lines (111 loc) · 3.64 KB

Weak Reference

Injecting WeakReference<T> lets a service hold a dependency without keeping it alive — useful for large, recreatable objects such as caches. Bind the underlying type as usual and request WeakReference<T>; the consumer then calls TryGetTarget, which returns false once the object has been garbage-collected.

using Shouldly;
using Pure.DI;

DI.Setup(nameof(Composition))
    .Bind<ILargeCache>().To<LargeCache>()
    .Bind<IService>().To<Service>()

    // Composition root
    .Root<IService>("MyService");

var composition = new Composition();
var service = composition.MyService;

// Represents a large memory object (e.g., a cache of images or large datasets)
interface ILargeCache;

class LargeCache : ILargeCache;

interface IService;

class Service(WeakReference<ILargeCache> cache) : IService
{
    public ILargeCache? Cache =>
        // Tries to retrieve the target object from the WeakReference.
        // If the object has been collected by the GC, it returns null.
        cache.TryGetTarget(out var value)
            ? value
            : null;
}
Running this code sample locally
dotnet --list-sdk
  • Create a net10.0 (or later) console application
dotnet new console -n Sample
dotnet add package Pure.DI
dotnet add package Shouldly
  • Copy the example code into the Program.cs file

You are ready to run the example 🚀

dotnet run

Note

WeakReference<T> is useful for caching scenarios where you want to allow garbage collection when memory is constrained.

The injected reference does not keep the target alive, so the consumer has to handle TryGetTarget returning false every time and recreate the value — Service.Cache returns null for that case. That makes the consumer's own code the cache, not the composition. A weak reference is only useful when something else holds the target strongly; if the dependency is transient and nobody else keeps it, it can be collected immediately after construction. Bind the target as Singleton (or hold it elsewhere) when the reference is expected to survive.

Tip

Prefer a normal reference when the lifetime of the object is known, and reach for WeakReference<T> only for optional, recreatable and genuinely large data.

The following partial class will be generated
partial class Composition
{
  public IService MyService
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    get
    {
      return new Service(new WeakReference<ILargeCache>(new LargeCache()));
    }
  }
}

Class diagram:

---
 config:
  class:
   hideEmptyMembersBox: true
---
classDiagram
	LargeCache --|> ILargeCache
	Service --|> IService
	Composition ..> Service : IService MyService
	Service *-- WeakReferenceᐸILargeCacheᐳ : WeakReferenceᐸILargeCacheᐳ
	WeakReferenceᐸILargeCacheᐳ *-- LargeCache : ILargeCache
	namespace Pure.DI.UsageTests.BCL.WeakReferenceScenario {
		class Composition {
		<<partial>>
		+IService MyService
		}
		class ILargeCache {
			<<interface>>
		}
		class IService {
			<<interface>>
		}
		class LargeCache {
				<<class>>
			+LargeCache()
		}
		class Service {
				<<class>>
			+Service(WeakReferenceᐸILargeCacheᐳ cache)
		}
	}
	namespace System {
		class WeakReferenceᐸILargeCacheᐳ {
				<<class>>
			+WeakReference(ILargeCache target)
		}
	}
Loading