{"record":{"id":"40cd3356fe6b3a92","repo":"dotnet/wpf","slug":"sr-enumerator-reachedend","errorCode":null,"errorMessage":"SR.Enumerator_ReachedEnd","messagePattern":"SR\\.Enumerator_ReachedEnd","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/FreezableCollection.cs","lineNumber":1079,"sourceCode":"            /// off the end of the list. However, the IEnumerable.Current\n            /// contract requires that we throw exceptions\n            /// </summary>\n            public T Current\n            {\n                get\n                {\n                    if (_index > -1)\n                    {\n                        return _current;\n                    }\n                    else if (_index == -1)\n                    {\n                        throw new InvalidOperationException(SR.Enumerator_NotStarted);\n                    }\n                    else\n                    {\n                        Debug.Assert(_index == -2, \"expected -2, got \" + _index + \"\\n\");\n                        throw new InvalidOperationException(SR.Enumerator_ReachedEnd);\n                    }\n                }\n            }\n\n            #endregion\n\n            #region Data\n            private T _current;\n            private FreezableCollection<T> _list;\n            private uint _version;\n            private int _index;\n            #endregion\n        }\n\n        private class SimpleMonitor : IDisposable\n        {\n            public void Enter()\n            {","sourceCodeStart":1061,"sourceCodeEnd":1097,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/FreezableCollection.cs#L1061-L1097","documentation":"FreezableCollection<T>.Enumerator.Current throws InvalidOperationException(SR.Enumerator_ReachedEnd) when accessed after enumeration has completed (_index == -2, i.e. MoveNext returned false and iteration went past the last element). Once exhausted, the enumerator has no current element.","triggerScenarios":"Reading Current after MoveNext() returned false — e.g. a do/while loop that reads Current after the terminating MoveNext, or accessing Current after a fully consumed foreach using the same enumerator object.","commonSituations":"Loops structured as 'while(true) { advanced = MoveNext(); var item = Current; ... }' where Current is read even when advanced is false, reusing an exhausted enumerator to 'get the last item'.","solutions":["Only read Current when MoveNext() returned true; capture the last item inside the loop before it ends.","Remember the last valid item in a local during iteration if you need it after the loop.","Create a fresh enumerator to iterate again instead of reading Current from the exhausted one."],"exampleFix":"// before\nwhile (e.MoveNext()) { }\nvar last = e.Current; // throws\n// after\nT last = default;\nwhile (e.MoveNext()) { last = e.Current; }","handlingStrategy":"validation","validationCode":"if (!e.MoveNext()) return; // empty or exhausted: do not read Current\nvar item = e.Current;","typeGuard":"bool TryPeekAfterMoveNext<T>(IEnumerator<T> e, out T value) { if (e.MoveNext()) { value = e.Current; return true; } value = default; return false; }","tryCatchPattern":"try { var cur = e.Current; }\ncatch (InvalidOperationException) { /* enumeration already finished */ }","preventionTips":["Read Current only inside a successful MoveNext branch","Track the last item in a local if needed after the loop","Re-enumerate instead of reusing an exhausted enumerator"],"tags":["wpf","enumerator","invalid-state","current"],"backgroundTag":"invalid-state-transition","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}