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:**

![image](https://github.com/protocolbuffers/protobuf/assets/303201/9dd3baa9-4432-446e-9049-1f7268d5be4c)

**MapField after:**

![image](https://github.com/protocolbuffers/protobuf/assets/303201/ac4aea33-e339-49e0-9a67-c174d2608393)

**RepeatedField before:**

![image](https://github.com/protocolbuffers/protobuf/assets/303201/16353785-bef4-4489-a3ab-de2437d51d4e)

**RepeatedField after:**

![image](https://github.com/protocolbuffers/protobuf/assets/303201/f3de7680-ded9-41d8-aac0-84a9e7b65c98)

**ByteString before:**

![image](https://github.com/protocolbuffers/protobuf/assets/303201/4febc400-1eb7-46ee-911e-a7698783a358)

**ByteString after:**

![image](https://github.com/protocolbuffers/protobuf/assets/303201/7635080e-9bb0-4f61-9a39-afbb9e575051)

**Descriptor before:**

![image](https://github.com/protocolbuffers/protobuf/assets/303201/5b89792b-a16a-4641-a50c-5355b5230b5d)

**Descriptor after:**

![image](https://github.com/protocolbuffers/protobuf/assets/303201/5047dc1e-c93b-43d5-bb8c-a6976a9ae6da)

**TypeRegistry before:**

![image](https://github.com/protocolbuffers/protobuf/assets/303201/d4aedf19-22cc-49b5-8717-9299e00abc85)

**TypeRegistry after:**

![image](https://github.com/protocolbuffers/protobuf/assets/303201/4a473595-74b9-40e2-96b8-2b103d5f44b0)

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();
+        }
     }
 }
diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
index 38e7015..8bf410a 100644
--- a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
+++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
@@ -10,7 +10,9 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.IO;
+using System.Linq;
 using System.Security;
 
 namespace Google.Protobuf.Collections
@@ -24,6 +26,8 @@
     /// supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases.
     /// </remarks>
     /// <typeparam name="T">The element type of the repeated field.</typeparam>
+    [DebuggerDisplay("Count = {Count}")]
+    [DebuggerTypeProxy(typeof(RepeatedField<>.RepeatedFieldDebugView))]
     public sealed class RepeatedField<T> : IList<T>, IList, IDeepCloneable<RepeatedField<T>>, IEquatable<RepeatedField<T>>, IReadOnlyList<T>
     {
         private static readonly EqualityComparer<T> EqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<T>();
@@ -642,5 +646,18 @@
             }
         }
         #endregion        
+
+        private sealed class RepeatedFieldDebugView
+        {
+            private readonly RepeatedField<T> list;
+
+            public RepeatedFieldDebugView(RepeatedField<T> list)
+            {
+                this.list = list;
+            }
+
+            [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
+            public T[] Items => list.ToArray();
+        }
     }
 }