From bb6f5f25c9192f6d37d8e9fccca90581eb65c24b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Oct 2025 20:07:03 +0000 Subject: [PATCH 1/9] Initial plan From 2626dfa8231966ff80418d6aafe832ad24fe118b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Oct 2025 20:42:19 +0000 Subject: [PATCH 2/9] Add index to OrderedDictionary debugger display Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../System/Collections/DebugView.Tests.cs | 9 +++ .../src/System.Collections.csproj | 1 + .../Collections/Generic/OrderedDictionary.cs | 2 +- .../Generic/OrderedDictionaryDebugView.cs | 57 +++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs diff --git a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs index 07b447c4c4de0f..0ce4b7fac0bb4d 100644 --- a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs @@ -21,6 +21,7 @@ private static IEnumerable TestDebuggerAttributes_GenericDictionaries( yield return new object[] { new ReadOnlyDictionary(new Dictionary()), new KeyValuePair[0] }; yield return new object[] { new SortedDictionary(), new KeyValuePair[0] }; yield return new object[] { new SortedList(), new KeyValuePair[0] }; + yield return new object[] { new OrderedDictionary(), new KeyValuePair[0] }; yield return new object[] { new Dictionary{{1, "One"}, {2, "Two"}}, new KeyValuePair[] @@ -69,6 +70,14 @@ private static IEnumerable TestDebuggerAttributes_GenericDictionaries( new ("[2]", "\"Two\""), } }; + + yield return new object[] { new OrderedDictionary{{1, "One"}, {2, "Two"}}, + new KeyValuePair[] + { + new ("[0/1]", "\"One\""), + new ("[1/2]", "\"Two\""), + } + }; } private static IEnumerable TestDebuggerAttributes_AdditionalGenericDictionaries() diff --git a/src/libraries/System.Collections/src/System.Collections.csproj b/src/libraries/System.Collections/src/System.Collections.csproj index bb7cfe2ad83cfb..54a2c4e9e694bc 100644 --- a/src/libraries/System.Collections/src/System.Collections.csproj +++ b/src/libraries/System.Collections/src/System.Collections.csproj @@ -17,6 +17,7 @@ + diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs index 8eec08838be6ba..7e806774efbbf3 100644 --- a/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs +++ b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs @@ -23,7 +23,7 @@ namespace System.Collections.Generic /// Operations on the collection have algorithmic complexities that are similar to that of the /// class, except with lookups by key similar in complexity to that of . /// - [DebuggerTypeProxy(typeof(IDictionaryDebugView<,>))] + [DebuggerTypeProxy(typeof(OrderedDictionaryDebugView<,>))] [DebuggerDisplay("Count = {Count}")] #if SYSTEM_COLLECTIONS public diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs new file mode 100644 index 00000000000000..df70535f0137da --- /dev/null +++ b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System.Collections.Generic +{ + internal sealed class OrderedDictionaryDebugView where TKey : notnull + { + private readonly OrderedDictionary _dictionary; + + public OrderedDictionaryDebugView(OrderedDictionary dictionary) + { + ArgumentNullException.ThrowIfNull(dictionary); + _dictionary = dictionary; + } + + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public DebugViewOrderedDictionaryItem[] Items + { + get + { + var items = new DebugViewOrderedDictionaryItem[_dictionary.Count]; + int index = 0; + foreach (KeyValuePair kvp in _dictionary) + { + items[index] = new DebugViewOrderedDictionaryItem(index, kvp.Key, kvp.Value); + index++; + } + return items; + } + } + } + + /// + /// Defines an index/key/value triple for displaying an item of an ordered dictionary by a debugger. + /// + [DebuggerDisplay("{Value}", Name = "[{Index}/{Key}]")] + internal readonly struct DebugViewOrderedDictionaryItem + { + public DebugViewOrderedDictionaryItem(int index, TKey key, TValue value) + { + Index = index; + Key = key; + Value = value; + } + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + public int Index { get; } + + [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] + public TKey Key { get; } + + [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] + public TValue Value { get; } + } +} From 284d2e92bfe97ee991ee8378306227d72f6b3e0c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Oct 2025 12:36:46 +0000 Subject: [PATCH 3/9] Change OrderedDictionary debug view to list-style format Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../System/Collections/DebugView.Tests.cs | 12 ++------ .../Generic/OrderedDictionaryDebugView.cs | 30 ++----------------- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs index 0ce4b7fac0bb4d..42b5c6753fa472 100644 --- a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs @@ -21,7 +21,6 @@ private static IEnumerable TestDebuggerAttributes_GenericDictionaries( yield return new object[] { new ReadOnlyDictionary(new Dictionary()), new KeyValuePair[0] }; yield return new object[] { new SortedDictionary(), new KeyValuePair[0] }; yield return new object[] { new SortedList(), new KeyValuePair[0] }; - yield return new object[] { new OrderedDictionary(), new KeyValuePair[0] }; yield return new object[] { new Dictionary{{1, "One"}, {2, "Two"}}, new KeyValuePair[] @@ -70,14 +69,6 @@ private static IEnumerable TestDebuggerAttributes_GenericDictionaries( new ("[2]", "\"Two\""), } }; - - yield return new object[] { new OrderedDictionary{{1, "One"}, {2, "Two"}}, - new KeyValuePair[] - { - new ("[0/1]", "\"One\""), - new ("[1/2]", "\"Two\""), - } - }; } private static IEnumerable TestDebuggerAttributes_AdditionalGenericDictionaries() @@ -175,6 +166,7 @@ private static IEnumerable TestDebuggerAttributes_ListInputs() yield return new object[] { new SortedList() }; yield return new object[] { new SortedSet() }; yield return new object[] { new Stack() }; + yield return new object[] { new OrderedDictionary() }; yield return new object[] { new Dictionary().Keys }; yield return new object[] { new Dictionary().Values }; @@ -202,6 +194,8 @@ private static IEnumerable TestDebuggerAttributes_ListInputs() stack.Push(2); yield return new object[] { stack }; + yield return new object[] { new OrderedDictionary { { 1, "One" }, { 2, "Two" } } }; + yield return new object[] { new SortedList { { "One", 1 }, { "Two", 2 } }.Keys }; yield return new object[] { new SortedList { { 1f, 1L }, { 2f, 2L } }.Values }; diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs index df70535f0137da..557f2f98910f99 100644 --- a/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs +++ b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs @@ -16,42 +16,18 @@ public OrderedDictionaryDebugView(OrderedDictionary dictionary) } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public DebugViewOrderedDictionaryItem[] Items + public KeyValuePair[] Items { get { - var items = new DebugViewOrderedDictionaryItem[_dictionary.Count]; + var items = new KeyValuePair[_dictionary.Count]; int index = 0; foreach (KeyValuePair kvp in _dictionary) { - items[index] = new DebugViewOrderedDictionaryItem(index, kvp.Key, kvp.Value); - index++; + items[index++] = kvp; } return items; } } } - - /// - /// Defines an index/key/value triple for displaying an item of an ordered dictionary by a debugger. - /// - [DebuggerDisplay("{Value}", Name = "[{Index}/{Key}]")] - internal readonly struct DebugViewOrderedDictionaryItem - { - public DebugViewOrderedDictionaryItem(int index, TKey key, TValue value) - { - Index = index; - Key = key; - Value = value; - } - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int Index { get; } - - [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] - public TKey Key { get; } - - [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] - public TValue Value { get; } - } } From 9a0bf3cb10145be4964ca8d9ac12cbbf2a453cda Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Oct 2025 14:28:55 +0000 Subject: [PATCH 4/9] Use string keys in OrderedDictionary test to distinguish from indices Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Common/tests/System/Collections/DebugView.Tests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs index 42b5c6753fa472..ffddfe0b5eca2b 100644 --- a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs @@ -166,7 +166,7 @@ private static IEnumerable TestDebuggerAttributes_ListInputs() yield return new object[] { new SortedList() }; yield return new object[] { new SortedSet() }; yield return new object[] { new Stack() }; - yield return new object[] { new OrderedDictionary() }; + yield return new object[] { new OrderedDictionary() }; yield return new object[] { new Dictionary().Keys }; yield return new object[] { new Dictionary().Values }; @@ -194,7 +194,7 @@ private static IEnumerable TestDebuggerAttributes_ListInputs() stack.Push(2); yield return new object[] { stack }; - yield return new object[] { new OrderedDictionary { { 1, "One" }, { 2, "Two" } } }; + yield return new object[] { new OrderedDictionary { { "One", "1" }, { "Two", "2" } } }; yield return new object[] { new SortedList { { "One", 1 }, { "Two", 2 } }.Keys }; yield return new object[] { new SortedList { { 1f, 1L }, { 2f, 2L } }.Values }; From 55a3368cd82aaa940d8deae882460ac4c1e4258c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Oct 2025 20:02:12 +0000 Subject: [PATCH 5/9] Fix build error: Use conditional DebuggerTypeProxy for OrderedDictionary Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../src/System/Collections/Generic/OrderedDictionary.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs index 7e806774efbbf3..b4745a5982015c 100644 --- a/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs +++ b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs @@ -23,7 +23,11 @@ namespace System.Collections.Generic /// Operations on the collection have algorithmic complexities that are similar to that of the /// class, except with lookups by key similar in complexity to that of . /// +#if SYSTEM_COLLECTIONS [DebuggerTypeProxy(typeof(OrderedDictionaryDebugView<,>))] +#else + [DebuggerTypeProxy(typeof(IDictionaryDebugView<,>))] +#endif [DebuggerDisplay("Count = {Count}")] #if SYSTEM_COLLECTIONS public From 1a46e032170373580e94b4c892db66f307bd40ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Oct 2025 06:45:21 +0000 Subject: [PATCH 6/9] Add test to validate OrderedDictionary debugger display format Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../System/Collections/DebugView.Tests.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs index ffddfe0b5eca2b..c12d93aebf1365 100644 --- a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs @@ -280,6 +280,31 @@ public static void TestDebuggerAttributes_Null(object obj) Assert.IsType(tie.InnerException); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsDebuggerTypeProxyAttributeSupported))] + public static void TestDebuggerAttributes_OrderedDictionary() + { + // Validate that OrderedDictionary displays as a list of KeyValuePairs with implicit indexing + var dict = new OrderedDictionary { { "One", "1" }, { "Two", "2" }, { "Three", "3" } }; + + DebuggerAttributes.ValidateDebuggerDisplayReferences(dict); + DebuggerAttributeInfo info = DebuggerAttributes.ValidateDebuggerTypeProxyProperties(dict); + PropertyInfo itemProperty = info.Properties.Single(pr => pr.GetCustomAttribute().State == DebuggerBrowsableState.RootHidden); + + // The debug view should return a KeyValuePair array + var items = itemProperty.GetValue(info.Instance) as Array; + Assert.NotNull(items); + Assert.Equal(3, items.Length); + + // Verify the items are KeyValuePairs in the correct order + var kvpArray = items.Cast>().ToArray(); + Assert.Equal("One", kvpArray[0].Key); + Assert.Equal("1", kvpArray[0].Value); + Assert.Equal("Two", kvpArray[1].Key); + Assert.Equal("2", kvpArray[1].Value); + Assert.Equal("Three", kvpArray[2].Key); + Assert.Equal("3", kvpArray[2].Value); + } + private class CustomKeyedCollection : KeyedCollection where TKey : notnull { public CustomKeyedCollection() : base() From 6b09d2ec2561cce74099e24b60c81d55f2a5e334 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Oct 2025 11:39:11 +0000 Subject: [PATCH 7/9] Remove conditional DebuggerTypeProxy by polyfilling OrderedDictionaryDebugView in System.Text.Json Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../src/System/Collections/Generic/OrderedDictionary.cs | 4 ---- src/libraries/System.Text.Json/src/System.Text.Json.csproj | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs index b4745a5982015c..7e806774efbbf3 100644 --- a/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs +++ b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs @@ -23,11 +23,7 @@ namespace System.Collections.Generic /// Operations on the collection have algorithmic complexities that are similar to that of the /// class, except with lookups by key similar in complexity to that of . /// -#if SYSTEM_COLLECTIONS [DebuggerTypeProxy(typeof(OrderedDictionaryDebugView<,>))] -#else - [DebuggerTypeProxy(typeof(IDictionaryDebugView<,>))] -#endif [DebuggerDisplay("Count = {Count}")] #if SYSTEM_COLLECTIONS public diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index cf127ba8b569a5..9f114fc6d1536b 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -375,6 +375,7 @@ The System.Text.Json library is built-in as part of the shared framework in .NET + From e63a19b88794edc1b100720fa95af25403c66973 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Oct 2025 21:42:10 +0000 Subject: [PATCH 8/9] Simplify OrderedDictionaryDebugView to use CopyTo Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../Collections/Generic/OrderedDictionaryDebugView.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs index 557f2f98910f99..a982215c7ef186 100644 --- a/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs +++ b/src/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionaryDebugView.cs @@ -20,12 +20,8 @@ public KeyValuePair[] Items { get { - var items = new KeyValuePair[_dictionary.Count]; - int index = 0; - foreach (KeyValuePair kvp in _dictionary) - { - items[index++] = kvp; - } + KeyValuePair[] items = new KeyValuePair[_dictionary.Count]; + ((ICollection>)_dictionary).CopyTo(items, 0); return items; } } From d7bade650d6197922ed2f2d9abe57299c708a1ae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Oct 2025 08:56:40 +0000 Subject: [PATCH 9/9] Fix build errors for .NET Framework by conditionally compiling OrderedDictionary tests Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Common/tests/System/Collections/DebugView.Tests.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs index c12d93aebf1365..b908cf13595a32 100644 --- a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs @@ -166,7 +166,9 @@ private static IEnumerable TestDebuggerAttributes_ListInputs() yield return new object[] { new SortedList() }; yield return new object[] { new SortedSet() }; yield return new object[] { new Stack() }; +#if !NETFRAMEWORK yield return new object[] { new OrderedDictionary() }; +#endif yield return new object[] { new Dictionary().Keys }; yield return new object[] { new Dictionary().Values }; @@ -194,7 +196,9 @@ private static IEnumerable TestDebuggerAttributes_ListInputs() stack.Push(2); yield return new object[] { stack }; +#if !NETFRAMEWORK yield return new object[] { new OrderedDictionary { { "One", "1" }, { "Two", "2" } } }; +#endif yield return new object[] { new SortedList { { "One", 1 }, { "Two", 2 } }.Keys }; yield return new object[] { new SortedList { { 1f, 1L }, { 2f, 2L } }.Values }; @@ -280,6 +284,7 @@ public static void TestDebuggerAttributes_Null(object obj) Assert.IsType(tie.InnerException); } +#if !NETFRAMEWORK [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsDebuggerTypeProxyAttributeSupported))] public static void TestDebuggerAttributes_OrderedDictionary() { @@ -304,6 +309,7 @@ public static void TestDebuggerAttributes_OrderedDictionary() Assert.Equal("Three", kvpArray[2].Key); Assert.Equal("3", kvpArray[2].Value); } +#endif private class CustomKeyedCollection : KeyedCollection where TKey : notnull {