Skip to content

Commit 1bc1c7d

Browse files
Enhance memory management guidelines with detailed IDisposable and async disposal patterns, including JavaScript interop cleanup and event handler management best practices.
1 parent 2f62297 commit 1bc1c7d

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

.github/copilot-instructions.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,63 @@
3030
- Lazy load components when possible
3131
- Use `ShouldRender()` to optimize rendering
3232

33+
## Memory Management & Leak Prevention
34+
### IDisposable/IAsyncDisposable Patterns
35+
- Always dispose `SemaphoreSlim` in try-finally blocks within DisposeAsync
36+
- Use disposal guard flags (`_disposed`) to prevent multiple disposals
37+
- Implement `IAsyncDisposable` for components using `CancellationTokenSource`
38+
- Dispose `CancellationTokenSource` in components (especially for animations/timers)
39+
- Call `Cancel()` before `Dispose()` on CancellationTokenSource
40+
41+
### JavaScript Interop Cleanup
42+
- Always dispose `DotNetObjectReference` instances in Dispose methods
43+
- Track event listeners in JavaScript and provide cleanup functions
44+
- Call JavaScript cleanup functions before disposing DotNetObjectReference
45+
- Use Map or similar structures to track handlers for proper cleanup
46+
- Example pattern:
47+
```javascript
48+
const _handlers = new Map();
49+
function setupListener(element, event, handler) {
50+
_handlers.set(`${event}-${element.id}`, handler);
51+
element.addEventListener(event, handler);
52+
}
53+
function cleanup() {
54+
_handlers.forEach((handler, key) => {
55+
const [event, elementId] = key.split('-');
56+
document.getElementById(elementId)?.removeEventListener(event, handler);
57+
});
58+
_handlers.clear();
59+
}
60+
```
61+
62+
### Async Operation Management
63+
- Avoid fire-and-forget async operations (`_ = SomeAsyncMethod()`)
64+
- Use `Task.Run()` with proper error handling for background operations
65+
- Always handle exceptions in background tasks
66+
- Use `CancellationToken` for long-running operations
67+
- Example safe pattern:
68+
```csharp
69+
Task.Run(async () => {
70+
try {
71+
await SomeAsyncOperation();
72+
} catch (Exception ex) {
73+
// Log error appropriately
74+
}
75+
});
76+
```
77+
78+
### Event Handler Cleanup
79+
- Remove all DOM event listeners in cleanup functions
80+
- Use AbortController for modern event listener cleanup when possible
81+
- Clean up MutationObserver instances
82+
- Remove global event handlers (window, document) on component disposal
83+
84+
### Service Disposal Best Practices
85+
- Implement disposal guards in all public methods of disposable services
86+
- Use ConfigureAwait(false) in disposal methods when possible
87+
- Dispose resources in reverse order of creation
88+
- Handle disposal of injected services appropriately
89+
3390
## Error Handling
3491
- Implement error boundaries
3592
- Use try-catch blocks in lifecycle methods

0 commit comments

Comments
 (0)