Project · Memory
Audit subscription and cache ownership
Trace two real retaining paths and verify their explicit end boundary without pretending to measure collection.
All C# source files below are loaded together in the playground. Files written by a run live in its virtual directory.
Program.cs
OwnershipScenario.Run();
Models/Document.cs
public sealed record Document(string Name, byte[] Preview);
Infrastructure/ChangeFeed.cs
public sealed class ChangeFeed
{
private event Action? Changed;
public int ListenerCount => Changed?.GetInvocationList().Length ?? 0;
public IDisposable Subscribe(Action handler)
{
Changed += handler;
return new Subscription(this, handler);
}
internal void Unsubscribe(Action handler) => Changed -= handler;
public void Publish() => Changed?.Invoke();
}
Infrastructure/Subscription.cs
public sealed class Subscription : IDisposable
{
private ChangeFeed? feed;
private Action? handler;
public Subscription(ChangeFeed feed, Action handler) { this.feed = feed; this.handler = handler; }
public void Dispose()
{
if (feed is null) return;
feed.Unsubscribe(handler!);
feed = null;
handler = null;
}
}
Cache/PreviewCache.cs
public sealed class PreviewCache
{
private readonly Dictionary<string, Document> items = new(StringComparer.Ordinal);
public int Count => items.Count;
public void Put(Document document) => items[document.Name] = document;
public void Clear() => items.Clear();
}
Labs/OwnershipScenario.cs
public static class OwnershipScenario
{
public static void Run()
{
var feed = new ChangeFeed();
var cache = new PreviewCache();
var document = new Document("rune", new byte[32]);
cache.Put(document);
using (var subscription = feed.Subscribe(() => Console.WriteLine("seen:" + document.Name)))
{
Console.WriteLine($"listeners:{feed.ListenerCount};cache:{cache.Count}");
feed.Publish();
}
cache.Clear();
Console.WriteLine($"listeners:{feed.ListenerCount};cache:{cache.Count}");
feed.Publish();
GC.KeepAlive(document);
}
}
OwnershipAudit.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>