dotnet/wpf · warning · ObjectDisposedException
SR.TextEditorSpellerInteropHasBeenDisposed
Error message
SR.TextEditorSpellerInteropHasBeenDisposed
What it means
NLGSpellerInterop.Dispose(bool) guards against double-disposal: if _isDisposed is already true, calling Dispose again throws ObjectDisposedException with SR.TextEditorSpellerInteropHasBeenDisposed rather than silently returning.
Solutions
- Track disposal in the owner and call Dispose only once (guard with a bool or Interlocked flag).
- Wrap the speller interop in a class that implements the standard dispose pattern tolerating multiple Dispose calls.
- Catch ObjectDisposedException around cleanup code in shutdown paths.
- Note: unlike most .NET types, this Dispose is not idempotent - check _isDisposed-visible state indirectly via calls that throw on use.
Example fix
// before
speller.Dispose();
speller.Dispose(); // throws
// after
if (!disposed)
{
speller.Dispose();
disposed = true;
} Defensive patterns
Strategy: try-catch
Try / catch
try { speller.Dispose(); }
catch (ObjectDisposedException) { /* already disposed */ } Prevention
- Single-owner disposal discipline
- Guard with your own disposed flag
- Avoid mixing explicit Dispose with using blocks on the same instance
When it happens
Trigger: Calling Dispose (or using/Dispose pattern completion) a second time on the same NLGSpellerInterop instance - e.g. explicit Dispose followed by a using block or finalizer-driven cleanup.
Common situations: Speller interop objects shared between TextEditor components and disposed by more than one owner; manual cleanup plus IDisposable dispose in the same shutdown path.
Related errors
- NLGSpellerInterop.SpellerSegment
- NLGSpellerInterop.SpellerSentence
- EncryptedPackageEnvelope object was disposed.
- FixedPageReader
- SR.ByteRangeDownloaderDisposed
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/cbea25b29dfc5ccb.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/NLGSpellerInterop.cs:116
// IDispose Methods
//
//------------------------------------------------------
#region IDispose Methods
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Internal interop resource cleanup
/// </summary>
protected override void Dispose(bool disposing)
{
if (_isDisposed)
throw new ObjectDisposedException(SR.TextEditorSpellerInteropHasBeenDisposed);
if (_textChunk != null)
{
Marshal.ReleaseComObject(_textChunk);
_textChunk = null;
}
// Stop the lifetime of Natural Language library
UnsafeNlMethods.NlUnload();
_isDisposed = true;
}
#endregion IDispose Methods
//------------------------------------------------------
//
// Internal MethodsView on GitHub (pinned to 81131a70a4)