Help us improve
Share bugs, ideas, or general feedback.
From dex-skill-dotnet-resources
.NET ресурсы и память — ловушки IDisposable, утечки, аллокации. Активируется при IDisposable, using, утечка памяти, memory leak, HttpClient, SocketException, connection timeout, dispose, event unsubscribe, StringBuilder, connection pool exhausted
How this skill is triggered — by the user, by Claude, or both
Slash command
/dex-skill-dotnet-resources:dotnet-resourcesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Плохо: `var conn = new SqlConnection(cs); conn.Open(); /* забыли Dispose */`
Share bugs, ideas, or general feedback.
Плохо: var conn = new SqlConnection(cs); conn.Open(); /* забыли Dispose */
Правильно: using var conn = new SqlConnection(cs); или await using
Почему: connection leak, пул соединений исчерпан → SqlException: Timeout expired
Плохо: var ms = new MemoryStream(); /* используем, не диспозим */
Правильно: using var ms = new MemoryStream(); — особенно критично для RecyclableMemoryStream
Почему: RecyclableMemoryStream не возвращается в пул без Dispose, стандартный MemoryStream держит буфер в LOH
Плохо: var reader = new StreamReader(stream); → Dispose() закроет stream
Правильно: new StreamReader(stream, leaveOpen: true) если stream нужен после
Почему: по умолчанию wrapper владеет потоком. Двойной close → ObjectDisposedException
Плохо: publisher.Changed += OnChanged; без соответствующего -=
Правильно: отписка в Dispose(): publisher.Changed -= OnChanged;
Почему: publisher держит ссылку на subscriber → subscriber не собирается GC. Особенно опасно для static events
Плохо: using var client = new HttpClient(); в каждом запросе или методе
Правильно: IHttpClientFactory → _factory.CreateClient()
Почему: new HttpClient() не переиспользует TCP. Dispose() не закрывает сокет сразу (TIME_WAIT) → socket exhaustion под нагрузкой
Плохо: foreach (var item in items) result += item; — O(n²) аллокаций
Правильно: string.Join(...) или StringBuilder.Append()
Почему: строка иммутабельна, каждая операция создаёт новый объект, GC pressure растёт квадратично
Плохо: new byte[100_000] на каждый запрос → LOH, фрагментация не устраняется GC
Правильно: ArrayPool<byte>.Shared.Rent(100_000) + try/finally { ArrayPool<byte>.Shared.Return(buffer) }
Почему: LOH собирается только при Gen2 GC, фрагментация приводит к OutOfMemoryException при наличии свободной памяти
Плохо: var buf = ArrayPool<byte>.Shared.Rent(size); /* используем, не возвращаем */
Правильно: try { ... } finally { ArrayPool<byte>.Shared.Return(buf); }
Почему: пул растёт бесконечно, выделяет новые сегменты, превращается в утечку памяти
Плохо: лямбда обращается к this.Field — в closure попадает весь this
Правильно: var field = this.Field; Action a = () => field; — копируй нужное в локальную переменную
Почему: объект не освобождается пока живёт лямбда/делегат, unexpected lifetime extension
Плохо: ~MyClass() { resource.Free(); } — только финализатор, без IDisposable
Правильно: полный Dispose pattern — IDisposable.Dispose() + GC.SuppressFinalize(this), финализатор как fallback
Почему: объект с финализатором переживает минимум одну дополнительную GC-коллекцию, финализатор-очередь однопоточная
Плохо: services.AddTransient<IMyService, MyService>() где MyService : IDisposable
Правильно: Scoped или явное управление через IServiceScopeFactory
Почему: контейнер трекает все Transient IDisposable до конца scope → накопление объектов в памяти
IDisposable: всегда using / await using, особенно SqlConnection, HttpClient (нет!), StreamHttpClient: только через IHttpClientFactoryArrayPool<T>.Shared с обязательным Return в finallyDispose()GC.SuppressFinalizeIDisposable, или явный scopenpx claudepluginhub dex-it/claude-code-marketplace --plugin dex-skill-dotnet-resourcesCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.