diff --git a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs index d363af3479c3bb..a67b7617ba681d 100644 --- a/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/DebugView.Tests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Reflection; @@ -11,14 +12,96 @@ namespace System.Collections.Tests { public class DebugView_Tests { - public static IEnumerable TestDebuggerAttributes_Inputs() + private static IEnumerable TestDebuggerAttributes_GenericDictionaries() + { + yield return new object[] { new Dictionary(), new KeyValuePair[0] }; + 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 Dictionary{{1, "One"}, {2, "Two"}}, + new KeyValuePair[] + { + new ("[1]", "\"One\""), + new ("[2]", "\"Two\""), + } + }; + yield return new object[] { new ReadOnlyDictionary(new Dictionary{{1, "One"}, {2, "Two"}}), + new KeyValuePair[] + { + new ("[1]", "\"One\""), + new ("[2]", "\"Two\""), + } + }; + yield return new object[] { new SortedDictionary{{"One", 1}, {"Two", 2}} , + new KeyValuePair[] + { + new ("[\"One\"]", "1"), + new ("[\"Two\"]", "2"), + } + }; + yield return new object[] { new SortedList { { "One", 1.0 }, { "Two", 2.0 } }, + new KeyValuePair[] + { + new ("[\"One\"]", "1"), + new ("[\"Two\"]", "2"), + } + }; + } + + private static IEnumerable TestDebuggerAttributes_NonGenericDictionaries() + { + yield return new object[] { new Hashtable(), new KeyValuePair[0] }; + yield return new object[] { Hashtable.Synchronized(new Hashtable()), new KeyValuePair[0] }; + yield return new object[] { new SortedList(), new KeyValuePair[0] }; + yield return new object[] { SortedList.Synchronized(new SortedList()), new KeyValuePair[0] }; + + yield return new object[] { new Hashtable { { "a", 1 }, { "b", "B" } }, + new KeyValuePair[] + { + new ("[\"a\"]", "1"), + new ("[\"b\"]", "\"B\""), + } + }; + yield return new object[] { Hashtable.Synchronized(new Hashtable { { "a", 1 }, { "b", "B" } }), + new KeyValuePair[] + { + new ("[\"a\"]", "1"), + new ("[\"b\"]", "\"B\""), + } + }; + yield return new object[] { new SortedList { { "a", 1 }, { "b", "B" } }, + new KeyValuePair[] + { + new ("[\"a\"]", "1"), + new ("[\"b\"]", "\"B\""), + } + }; + yield return new object[] { SortedList.Synchronized(new SortedList { { "a", 1 }, { "b", "B" } }), + new KeyValuePair[] + { + new ("[\"a\"]", "1"), + new ("[\"b\"]", "\"B\""), + } + }; +#if !NETFRAMEWORK // ListDictionaryInternal in .Net Framework is not annotated with debugger attributes. + yield return new object[] { new Exception().Data, new KeyValuePair[0] }; + yield return new object[] { new Exception { Data = { { "a", 1 }, { "b", "B" } } }.Data, + new KeyValuePair[] + { + new ("[\"a\"]", "1"), + new ("[\"b\"]", "\"B\""), + } + }; +#endif + } + + private static IEnumerable TestDebuggerAttributes_ListInputs() { - yield return new object[] { new Dictionary() }; yield return new object[] { new HashSet() }; yield return new object[] { new LinkedList() }; yield return new object[] { new List() }; yield return new object[] { new Queue() }; - yield return new object[] { new SortedDictionary() }; yield return new object[] { new SortedList() }; yield return new object[] { new SortedSet() }; yield return new object[] { new Stack() }; @@ -30,39 +113,83 @@ public static IEnumerable TestDebuggerAttributes_Inputs() yield return new object[] { new SortedList().Keys }; yield return new object[] { new SortedList().Values }; - yield return new object[] { new Dictionary{{1, "One"}, {2, "Two"}} }; - yield return new object[] { new HashSet{"One", "Two"} }; + yield return new object[] { new HashSet { "One", "Two" } }; - LinkedList linkedList = new LinkedList(); + LinkedList linkedList = new(); linkedList.AddFirst(1); linkedList.AddLast(2); yield return new object[] { linkedList }; - yield return new object[] { new List{1, 2} }; + yield return new object[] { new List { 1, 2 } }; - Queue queue = new Queue(); + Queue queue = new(); queue.Enqueue(1); queue.Enqueue(2); yield return new object[] { queue }; - yield return new object[] { new SortedDictionary{{"One", 1}, {"Two", 2}} }; - yield return new object[] { new SortedList{{1, "One"}, {2, "Two"}} }; - yield return new object[] { new SortedSet{1, 2} }; + yield return new object[] { new SortedSet { 1, 2 } }; - var stack = new Stack(); + Stack stack = new(); stack.Push(1); stack.Push(2); yield return new object[] { stack }; - yield return new object[] { new Dictionary{{1.0, 1.0f}, {2.0, 2.0f}}.Keys }; - yield return new object[] { new Dictionary{{1.0f, 1.0}, {2.0f, 2.0}}.Values }; - yield return new object[] { new SortedDictionary{{Guid.NewGuid(), "One"}, {Guid.NewGuid(), "Two"}}.Keys }; - yield return new object[] { new SortedDictionary{{1L, Guid.NewGuid()}, {2L, Guid.NewGuid()}}.Values }; - yield return new object[] { new SortedList{{"One", 1}, {"Two", 2}}.Keys }; - yield return new object[] { new SortedList{{1f, 1L}, {2f, 2L}}.Values }; + yield return new object[] { new SortedList { { "One", 1 }, { "Two", 2 } }.Keys }; + yield return new object[] { new SortedList { { 1f, 1L }, { 2f, 2L } }.Values }; + + yield return new object[] { new Dictionary { { 1.0, 1.0f }, { 2.0, 2.0f } }.Keys }; + yield return new object[] { new Dictionary { { 1.0f, 1.0 }, { 2.0f, 2.0 } }.Values }; + yield return new object[] { new SortedDictionary { { Guid.NewGuid(), "One" }, { Guid.NewGuid(), "Two" } }.Keys }; + yield return new object[] { new SortedDictionary { { 1L, Guid.NewGuid() }, { 2L, Guid.NewGuid() } }.Values }; + } + + public static IEnumerable TestDebuggerAttributes_InputsPresentedAsDictionary() + { +#if !NETFRAMEWORK + return TestDebuggerAttributes_NonGenericDictionaries() + .Concat(TestDebuggerAttributes_GenericDictionaries()); +#else + // In .Net Framework only non-generic dictionaries are displayed in a dictionary format by the debugger. + return TestDebuggerAttributes_NonGenericDictionaries(); +#endif + } + + public static IEnumerable TestDebuggerAttributes_InputsPresentedAsList() + { +#if !NETFRAMEWORK + return TestDebuggerAttributes_ListInputs(); +#else + // In .Net Framework generic dictionaries are displayed in a list format by the debugger. + return TestDebuggerAttributes_GenericDictionaries() + .Select(t => new[] { t[0] }) + .Concat(TestDebuggerAttributes_ListInputs()); +#endif + } + + public static IEnumerable TestDebuggerAttributes_Inputs() + { + return TestDebuggerAttributes_InputsPresentedAsDictionary() + .Select(t => new[] { t[0] }) + .Concat(TestDebuggerAttributes_InputsPresentedAsList()); } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsDebuggerTypeProxyAttributeSupported))] - [MemberData(nameof(TestDebuggerAttributes_Inputs))] - public static void TestDebuggerAttributes(object obj) + [MemberData(nameof(TestDebuggerAttributes_InputsPresentedAsDictionary))] + public static void TestDebuggerAttributes_Dictionary(IDictionary obj, KeyValuePair[] expected) + { + DebuggerAttributes.ValidateDebuggerDisplayReferences(obj); + DebuggerAttributeInfo info = DebuggerAttributes.ValidateDebuggerTypeProxyProperties(obj); + PropertyInfo itemProperty = info.Properties.Single(pr => pr.GetCustomAttribute().State == DebuggerBrowsableState.RootHidden); + Array itemArray = (Array)itemProperty.GetValue(info.Instance); + List> formatted = itemArray.Cast() + .Select(DebuggerAttributes.ValidateFullyDebuggerDisplayReferences) + .Select(formattedResult => new KeyValuePair(formattedResult.Key, formattedResult.Value)) + .ToList(); + + CollectionAsserts.EqualUnordered((ICollection)expected, formatted); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsDebuggerTypeProxyAttributeSupported))] + [MemberData(nameof(TestDebuggerAttributes_InputsPresentedAsList))] + public static void TestDebuggerAttributes_List(object obj) { DebuggerAttributes.ValidateDebuggerDisplayReferences(obj); DebuggerAttributeInfo info = DebuggerAttributes.ValidateDebuggerTypeProxyProperties(obj); diff --git a/src/libraries/Common/tests/System/Diagnostics/DebuggerAttributes.cs b/src/libraries/Common/tests/System/Diagnostics/DebuggerAttributes.cs index ee6853131e5d15..f0211c2113c2d1 100644 --- a/src/libraries/Common/tests/System/Diagnostics/DebuggerAttributes.cs +++ b/src/libraries/Common/tests/System/Diagnostics/DebuggerAttributes.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Diagnostics; +using System.Data; using System.Linq; using System.Reflection; using System.Text; @@ -15,6 +15,13 @@ internal class DebuggerAttributeInfo public IEnumerable Properties { get; set; } } + internal class DebuggerDisplayResult + { + public string Value { get; set; } + public string Key { get; set; } + public string Type { get; set; } + } + internal static class DebuggerAttributes { internal static object GetFieldValue(object obj, string fieldName) @@ -86,18 +93,52 @@ public static IEnumerable GetDebuggerVisibleProperties(Type debugg public static Type GetProxyType(Type type) => GetProxyType(type, type.GenericTypeArguments); - private static Type GetProxyType(Type type, Type[] genericTypeArguments) + internal static DebuggerDisplayResult ValidateFullyDebuggerDisplayReferences(object obj) + { + CustomAttributeData cad = FindAttribute(obj.GetType(), attributeType: typeof(DebuggerDisplayAttribute)); + + // Get the text of the DebuggerDisplayAttribute + string attrText = (string)cad.ConstructorArguments[0].Value; + string formattedValue = EvaluateDisplayString(attrText, obj); + + string formattedKey = FormatDebuggerDisplayNamedArgument(nameof(DebuggerDisplayAttribute.Name), cad, obj); + string formattedType = FormatDebuggerDisplayNamedArgument(nameof(DebuggerDisplayAttribute.Type), cad, obj); + + return new DebuggerDisplayResult { Value = formattedValue, Key = formattedKey, Type = formattedType }; + } + + internal static string ValidateDebuggerDisplayReferences(object obj) + { + CustomAttributeData cad = FindAttribute(obj.GetType(), attributeType: typeof(DebuggerDisplayAttribute)); + + // Get the text of the DebuggerDisplayAttribute + string attrText = (string)cad.ConstructorArguments[0].Value; + + return EvaluateDisplayString(attrText, obj); + } + + private static CustomAttributeData FindAttribute(Type type, Type attributeType) { - // Get the DebuggerTypeProxyAttribute for obj - CustomAttributeData[] attrs = - type.GetTypeInfo().CustomAttributes - .Where(a => a.AttributeType == typeof(DebuggerTypeProxyAttribute)) - .ToArray(); - if (attrs.Length != 1) + for (Type t = type; t != null; t = t.BaseType) { - throw new InvalidOperationException($"Expected one DebuggerTypeProxyAttribute on {type}."); + CustomAttributeData[] attributes = t.GetTypeInfo().CustomAttributes + .Where(a => a.AttributeType == attributeType) + .ToArray(); + if (attributes.Length != 0) + { + if (attributes.Length > 1) + { + throw new InvalidOperationException($"Expected one {attributeType.Name} on {type} but found more."); + } + return attributes[0]; + } } - CustomAttributeData cad = attrs[0]; + throw new InvalidOperationException($"Expected one {attributeType.Name} on {type}."); + } + + private static Type GetProxyType(Type type, Type[] genericTypeArguments) + { + CustomAttributeData cad = FindAttribute(type, attributeType: typeof(DebuggerTypeProxyAttribute)); Type proxyType = cad.ConstructorArguments[0].ArgumentType == typeof(Type) ? (Type)cad.ConstructorArguments[0].Value : @@ -110,24 +151,24 @@ private static Type GetProxyType(Type type, Type[] genericTypeArguments) return proxyType; } - internal static string ValidateDebuggerDisplayReferences(object obj) + private static string FormatDebuggerDisplayNamedArgument(string argumentName, CustomAttributeData debuggerDisplayAttributeData, object obj) { - // Get the DebuggerDisplayAttribute for obj - Type objType = obj.GetType(); - CustomAttributeData[] attrs = - objType.GetTypeInfo().CustomAttributes - .Where(a => a.AttributeType == typeof(DebuggerDisplayAttribute)) - .ToArray(); - if (attrs.Length != 1) + CustomAttributeNamedArgument namedAttribute = debuggerDisplayAttributeData.NamedArguments.FirstOrDefault(na => na.MemberName == argumentName); + if (namedAttribute != default) { - throw new InvalidOperationException($"Expected one DebuggerDisplayAttribute on {objType}."); + string? value = (string?)namedAttribute.TypedValue.Value; + if (!string.IsNullOrEmpty(value)) + { + return EvaluateDisplayString(value, obj); + } } - CustomAttributeData cad = attrs[0]; - - // Get the text of the DebuggerDisplayAttribute - string attrText = (string)cad.ConstructorArguments[0].Value; + return ""; + } - string[] segments = attrText.Split(new[] { '{', '}' }); + private static string EvaluateDisplayString(string displayString, object obj) + { + Type objType = obj.GetType(); + string[] segments = displayString.Split(['{', '}']); if (segments.Length % 2 == 0) { diff --git a/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj b/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj index 5fe02fe3551b12..7844617737cafd 100644 --- a/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj +++ b/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj @@ -13,8 +13,8 @@ - + diff --git a/src/libraries/System.Collections.NonGeneric/src/System/Collections/SortedList.cs b/src/libraries/System.Collections.NonGeneric/src/System/Collections/SortedList.cs index 720c1fd7a83869..df3ea3e0364256 100644 --- a/src/libraries/System.Collections.NonGeneric/src/System/Collections/SortedList.cs +++ b/src/libraries/System.Collections.NonGeneric/src/System/Collections/SortedList.cs @@ -11,6 +11,7 @@ ** ===========================================================*/ +using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -351,12 +352,12 @@ public virtual void CopyTo(Array array, int arrayIndex) // KeyValuePairs is different from Dictionary Entry in that it has special // debugger attributes on its fields. - internal virtual KeyValuePairs[] ToKeyValuePairsArray() + internal virtual DebugViewDictionaryItem[] ToDebugViewDictionaryItemArray() { - KeyValuePairs[] array = new KeyValuePairs[Count]; + var array = new DebugViewDictionaryItem[Count]; for (int i = 0; i < Count; i++) { - array[i] = new KeyValuePairs(keys[i], values[i]); + array[i] = new DebugViewDictionaryItem(keys[i], values[i]); } return array; } @@ -766,9 +767,9 @@ public override void SetByIndex(int index, object? value) } } - internal override KeyValuePairs[] ToKeyValuePairsArray() + internal override DebugViewDictionaryItem[] ToDebugViewDictionaryItemArray() { - return _list.ToKeyValuePairsArray(); + return _list.ToDebugViewDictionaryItemArray(); } public override void TrimToSize() @@ -1097,11 +1098,11 @@ public SortedListDebugView(SortedList sortedList) } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public KeyValuePairs[] Items + public DebugViewDictionaryItem[] Items { get { - return _sortedList.ToKeyValuePairsArray(); + return _sortedList.ToDebugViewDictionaryItemArray(); } } } diff --git a/src/libraries/System.Collections.NonGeneric/tests/SortedListTests.cs b/src/libraries/System.Collections.NonGeneric/tests/SortedListTests.cs index 5c6d37db7db9e4..1b5378dfea8d3f 100644 --- a/src/libraries/System.Collections.NonGeneric/tests/SortedListTests.cs +++ b/src/libraries/System.Collections.NonGeneric/tests/SortedListTests.cs @@ -223,19 +223,21 @@ public void DebuggerAttribute_NormalList() { var list = new SortedList() { { "a", 1 }, { "b", 2 } }; DebuggerAttributeInfo debuggerAttribute = DebuggerAttributes.ValidateDebuggerTypeProxyProperties(list); - PropertyInfo infoProperty = debuggerAttribute.Properties.Single(property => property.Name == "Items"); - object[] items = (object[])infoProperty.GetValue(debuggerAttribute.Instance); - Assert.Equal(list.Count, items.Length); + PropertyInfo itemProperty = debuggerAttribute.Properties.Single(pr => pr.GetCustomAttribute().State == DebuggerBrowsableState.RootHidden); + Array itemArray = (Array)itemProperty.GetValue(debuggerAttribute.Instance); + + Assert.Equal(list.Count, itemArray.Length); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsDebuggerTypeProxyAttributeSupported))] public void DebuggerAttribute_SynchronizedList() { var list = SortedList.Synchronized(new SortedList() { { "a", 1 }, { "b", 2 } }); - DebuggerAttributeInfo debuggerAttribute = DebuggerAttributes.ValidateDebuggerTypeProxyProperties(typeof(SortedList), list); - PropertyInfo infoProperty = debuggerAttribute.Properties.Single(property => property.Name == "Items"); - object[] items = (object[])infoProperty.GetValue(debuggerAttribute.Instance); - Assert.Equal(list.Count, items.Length); + DebuggerAttributeInfo debuggerAttribute = DebuggerAttributes.ValidateDebuggerTypeProxyProperties(list); + PropertyInfo itemProperty = debuggerAttribute.Properties.Single(pr => pr.GetCustomAttribute().State == DebuggerBrowsableState.RootHidden); + Array itemArray = (Array)itemProperty.GetValue(debuggerAttribute.Instance); + + Assert.Equal(list.Count, itemArray.Length); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsDebuggerTypeProxyAttributeSupported))] diff --git a/src/libraries/System.Collections/src/System.Collections.csproj b/src/libraries/System.Collections/src/System.Collections.csproj index a7e8976d48bfcd..17b09933523e8e 100644 --- a/src/libraries/System.Collections/src/System.Collections.csproj +++ b/src/libraries/System.Collections/src/System.Collections.csproj @@ -7,6 +7,8 @@ + pr.GetCustomAttribute().State == DebuggerBrowsableState.RootHidden); - KeyValuePair[] pairs = itemProperty.GetValue(info.Instance) as KeyValuePair[]; - Assert.Equal(dict, pairs); + Array itemArray = (Array)itemProperty.GetValue(info.Instance); + Assert.Equal(dict.Count, itemArray.Length); DebuggerAttributes.ValidateDebuggerDisplayReferences(dict.Keys); info = DebuggerAttributes.ValidateDebuggerTypeProxyProperties(typeof(ReadOnlyDictionary.KeyCollection), new Type[] { typeof(int) }, dict.Keys); diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 6998e54610c793..e3fc18bfdafbee 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -183,6 +183,7 @@ + @@ -227,7 +228,6 @@ - diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/DebugViewDictionaryItem.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/DebugViewDictionaryItem.cs new file mode 100644 index 00000000000000..4088c1f2a4fdd9 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/DebugViewDictionaryItem.cs @@ -0,0 +1,32 @@ +// 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 +{ + /// + /// Defines a key/value pair for displaying an item of a dictionary by a debugger. + /// + [DebuggerDisplay("{Value}", Name = "[{Key}]")] + internal readonly struct DebugViewDictionaryItem + { + public DebugViewDictionaryItem(TKey key, TValue value) + { + Key = key; + Value = value; + } + + public DebugViewDictionaryItem(KeyValuePair keyValue) + { + Key = keyValue.Key; + Value = keyValue.Value; + } + + [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] + public TKey Key { get; } + + [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] + public TValue Value { get; } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionaryDebugView.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionaryDebugView.cs index 97e32ad5da7df5..c082d31a09ff8b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionaryDebugView.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionaryDebugView.cs @@ -5,11 +5,11 @@ namespace System.Collections.Generic { - internal sealed class IDictionaryDebugView where K : notnull + internal sealed class IDictionaryDebugView where TKey : notnull { - private readonly IDictionary _dict; + private readonly IDictionary _dict; - public IDictionaryDebugView(IDictionary dictionary) + public IDictionaryDebugView(IDictionary dictionary) { ArgumentNullException.ThrowIfNull(dictionary); @@ -17,12 +17,17 @@ public IDictionaryDebugView(IDictionary dictionary) } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public KeyValuePair[] Items + public DebugViewDictionaryItem[] Items { get { - KeyValuePair[] items = new KeyValuePair[_dict.Count]; - _dict.CopyTo(items, 0); + var keyValuePairs = new KeyValuePair[_dict.Count]; + _dict.CopyTo(keyValuePairs, 0); + var items = new DebugViewDictionaryItem[keyValuePairs.Length]; + for (int i = 0; i < items.Length; i++) + { + items[i] = new DebugViewDictionaryItem(keyValuePairs[i]); + } return items; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Hashtable.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Hashtable.cs index a46b52c7334110..def27e549d8d2d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Hashtable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Hashtable.cs @@ -11,6 +11,7 @@ ** ===========================================================*/ +using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -581,13 +582,9 @@ public virtual void CopyTo(Array array, int arrayIndex) CopyEntries(array, arrayIndex); } - // Copies the values in this Hashtable to an KeyValuePairs array. - // KeyValuePairs is different from Dictionary Entry in that it has special - // debugger attributes on its fields. - - internal virtual KeyValuePairs[] ToKeyValuePairsArray() + internal virtual DebugViewDictionaryItem[] ToDebugViewDictionaryItemArray() { - KeyValuePairs[] array = new KeyValuePairs[_count]; + var array = new DebugViewDictionaryItem[_count]; int index = 0; Bucket[] lbuckets = _buckets; for (int i = lbuckets.Length; --i >= 0;) @@ -595,7 +592,7 @@ internal virtual KeyValuePairs[] ToKeyValuePairsArray() object? keyv = lbuckets[i].key; if ((keyv != null) && (keyv != _buckets)) { - array[index++] = new KeyValuePairs(keyv, lbuckets[i].val); + array[index++] = new DebugViewDictionaryItem(keyv, lbuckets[i].val); } } @@ -1385,9 +1382,9 @@ public override void OnDeserialization(object? sender) // call OnDeserialization on our parent table. } - internal override KeyValuePairs[] ToKeyValuePairsArray() + internal override DebugViewDictionaryItem[] ToDebugViewDictionaryItemArray() { - return _table.ToKeyValuePairsArray(); + return _table.ToDebugViewDictionaryItemArray(); } } @@ -1509,7 +1506,7 @@ public HashtableDebugView(Hashtable hashtable) } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public KeyValuePairs[] Items => _hashtable.ToKeyValuePairsArray(); + public DebugViewDictionaryItem[] Items => _hashtable.ToDebugViewDictionaryItemArray(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/KeyValuePairs.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/KeyValuePairs.cs deleted file mode 100644 index 87543d938751b1..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/KeyValuePairs.cs +++ /dev/null @@ -1,26 +0,0 @@ -// 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 -{ - /// - /// Defines key/value pairs for displaying items in a collection class under the debugger. - /// - [DebuggerDisplay("{_value}", Name = "[{_key}]")] - internal sealed class KeyValuePairs - { - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private readonly object _key; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private readonly object? _value; - - public KeyValuePairs(object key, object? value) - { - _value = value; - _key = key; - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/ListDictionaryInternal.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/ListDictionaryInternal.cs index 730356461254dd..3dc89a50ea9716 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/ListDictionaryInternal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/ListDictionaryInternal.cs @@ -1,5 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -418,15 +419,15 @@ public ListDictionaryInternalDebugView(ListDictionaryInternal list) } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public KeyValuePairs[] Items + public DebugViewDictionaryItem[] Items { get { - var array = new KeyValuePairs[_list.count]; + var array = new DebugViewDictionaryItem[_list.count]; int index = 0; for (DictionaryNode? node = _list.head; node != null; node = node.next) { - array[index++] = new KeyValuePairs(node.key, node.value); + array[index++] = new DebugViewDictionaryItem(node.key, node.value); } return array; }