Add .NET debugging attributes (#14097)
I've been working with a large Protobuf model and noticed debugging issues that can easily be improved.
Add debugging attributes to collections, `ByteString`, and descriptors. No impact on runtime behavior. Debugger type proxies are what the debugger displays by default, but full data is available by selecting "Raw View".
`RepeatedField` and `MapField` now display their item count. This is standard across .NET collections. For example, .NET's list and dictionary both display `Count = {Count}`.
Note that previously, Protobuf collections displayed the result of `ToString`, which returned JSON. The JSON debug view isn't useful when there is too much content to display at once because it's truncated. That experience will be fairly common.
Count benefits:
* Always useful
* Makes debugging Protobuf collections feel more like regular .NET collections
* Collection contents is now easier to access with debugger type proxies
No dependency between this PR and https://github.com/protocolbuffers/protobuf/pull/13838. Each can be merged independently.
**MapField before:**

**MapField after:**

**RepeatedField before:**

**RepeatedField after:**

**ByteString before:**

**ByteString after:**

**Descriptor before:**

**Descriptor after:**

**TypeRegistry before:**

**TypeRegistry after:**

Closes #14097
COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/14097 from JamesNK:jamesnk/debugging f0dea3464d471042a59e9c0000a5e65e8c9bc46b
PiperOrigin-RevId: 568444117
diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
index 2e18976..f0be958 100644
--- a/csharp/src/Google.Protobuf/Collections/MapField.cs
+++ b/csharp/src/Google.Protobuf/Collections/MapField.cs
@@ -11,6 +11,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security;
@@ -43,6 +44,8 @@
/// in future versions.
/// </para>
/// </remarks>
+ [DebuggerDisplay("Count = {Count}")]
+ [DebuggerTypeProxy(typeof(MapField<,>.MapFieldDebugView))]
public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary, IReadOnlyDictionary<TKey, TValue>
{
private static readonly EqualityComparer<TValue> ValueEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<TValue>();
@@ -683,5 +686,18 @@
}
}
}
+
+ private sealed class MapFieldDebugView
+ {
+ private readonly MapField<TKey, TValue> map;
+
+ public MapFieldDebugView(MapField<TKey, TValue> map)
+ {
+ this.map = map;
+ }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
+ public KeyValuePair<TKey, TValue>[] Items => map.list.ToArray();
+ }
}
}