{"record":{"id":"ed08431a0a502f8f","repo":"dotnet/wpf","slug":"nlgspellerinterop-spellersegment","errorCode":null,"errorMessage":"NLGSpellerInterop.SpellerSegment","messagePattern":"NLGSpellerInterop\\.SpellerSegment","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"warning","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/NLGSpellerInterop.cs","lineNumber":743,"sourceCode":"                }\n            }\n\n\n            #endregion SpellerInteropBase.ISpellerSegment\n\n            #region IDisposable\n\n            public void Dispose()\n            {\n                Dispose(true);\n                GC.SuppressFinalize(this);\n            }\n\n            protected virtual void Dispose(bool disposing)\n            {\n                if (_disposed)\n                {\n                    throw new ObjectDisposedException(\"NLGSpellerInterop.SpellerSegment\");\n                }\n\n                if (_subSegments != null)\n                {\n                    foreach (SpellerSegment subSegment in _subSegments)\n                    {\n                        // Don't call Dispose(disposing) here. That will \n                        // fail to suppress finalization of subsegment objects.\n                        subSegment.Dispose();\n                    }\n                    _subSegments = null;\n                }\n\n                if (_textSegment != null)\n                {\n                    Marshal.ReleaseComObject(_textSegment);\n                    _textSegment = null;\n                }","sourceCodeStart":725,"sourceCodeEnd":761,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/NLGSpellerInterop.cs#L725-L761","documentation":"NLGSpellerInterop.SpellerSegment.Dispose(bool) throws ObjectDisposedException (message \"NLGSpellerInterop.SpellerSegment\") when Dispose is called on an already-disposed segment. Like the outer interop class, this nested type's Dispose is not idempotent.","triggerScenarios":"Disposing a SpellerSegment twice - e.g. iterating subSegments and disposing each, then disposing parent segments that dispose their children again, or explicit plus finalizer cleanup.","commonSituations":"Manual spell-check span management where both the sentence loop and segment loop release the same child segments; repeated teardown after spell-check cancellation.","solutions":["Dispose each SpellerSegment exactly once; let SpellerSentence own and dispose its segments.","Add an ownership convention: only the parent (sentence) disposes segments.","Catch ObjectDisposedException in bulk cleanup loops.","Null out references after disposal to prevent accidental re-disposal."],"exampleFix":"// before\nforeach (var seg in sentence.Segments) seg.Dispose();\nsentence.Dispose(); // may double-dispose segments\n// after\nsentence.Dispose(); // sentence disposes its own segments once","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { segment.Dispose(); }\ncatch (ObjectDisposedException) { /* ignore in cleanup */ }","preventionTips":["Let SpellerSentence own segment lifetime","Never dispose both parent and child explicitly","Null out segment references after disposal"],"tags":["dispose","wpf","spellcheck","object-disposed"],"backgroundTag":"object-disposed","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}