Fix MemoryDebugView and override Memory.ToString similar to Span (#16732)
authorAhson Khan <ahkha@microsoft.com>
Sun, 4 Mar 2018 01:55:31 +0000 (17:55 -0800)
committerGitHub <noreply@github.com>
Sun, 4 Mar 2018 01:55:31 +0000 (17:55 -0800)
* Fix MemoryDebugView and add Memory.ToString similar to Span

* Simplify implementation of ToString

src/mscorlib/shared/System/Memory.cs
src/mscorlib/shared/System/MemoryDebugView.cs
src/mscorlib/shared/System/ReadOnlyMemory.cs

index fca015f..82c66d6 100644 (file)
@@ -18,8 +18,8 @@ namespace System
     /// Memory represents a contiguous region of arbitrary memory similar to <see cref="Span{T}"/>.
     /// Unlike <see cref="Span{T}"/>, it is not a byref-like type.
     /// </summary>
-    [DebuggerDisplay("{DebuggerDisplay,nq}")]
     [DebuggerTypeProxy(typeof(MemoryDebugView<>))]
+    [DebuggerDisplay("{ToString(),raw}")]
     public readonly struct Memory<T>
     {
         // NOTE: With the current implementation, Memory<T> and ReadOnlyMemory<T> must have the same layout,
@@ -145,9 +145,6 @@ namespace System
         public static implicit operator ReadOnlyMemory<T>(Memory<T> memory) =>
             Unsafe.As<Memory<T>, ReadOnlyMemory<T>>(ref memory);
 
-        //Debugger Display = {T[length]}
-        private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length);
-
         /// <summary>
         /// Returns an empty <see cref="Memory{T}"/>
         /// </summary>
@@ -164,6 +161,19 @@ namespace System
         public bool IsEmpty => _length == 0;
 
         /// <summary>
+        /// For <see cref="Memory{Char}"/>, returns a new instance of string that represents the characters pointed to by the memory.
+        /// Otherwise, returns a <see cref="string"/> with the name of the type and the number of elements.
+        /// </summary>
+        public override string ToString()
+        {
+            if (typeof(T) == typeof(char))
+            {
+                return (_object is string str) ? str.Substring(_index, _length) : Span.ToString();
+            }
+            return string.Format("System.Memory<{0}>[{1}]", typeof(T).Name, _length);
+        }
+
+        /// <summary>
         /// Forms a slice out of the given memory, beginning at 'start'.
         /// </summary>
         /// <param name="start">The index at which to begin this slice.</param>
index b1ed881..f56a67c 100644 (file)
@@ -22,31 +22,6 @@ namespace System
         }
 
         [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
-        public T[] Items
-        {
-            // This is a work around since we cannot use _memory.ToArray() due to
-            // https://devdiv.visualstudio.com/DevDiv/_workitems?id=286592
-            get
-            {
-                if (MemoryMarshal.TryGetArray(_memory, out ArraySegment<T> segment))
-                {
-                    T[] array = new T[_memory.Length];
-                    Array.Copy(segment.Array, segment.Offset, array, 0, array.Length);
-                    return array;
-                }
-
-                if (typeof(T) == typeof(char) &&
-                    MemoryMarshal.TryGetString((ReadOnlyMemory<char>)(object)_memory, out string text, out int start, out int length))
-                {
-                    return (T[])(object)text.Substring(start, length).ToCharArray();
-                }
-
-#if FEATURE_PORTABLE_SPAN
-                return SpanHelpers.PerTypeValues<T>.EmptyArray;
-#else
-                return Array.Empty<T>();
-#endif // FEATURE_PORTABLE_SPAN
-            }
-        }
+        public T[] Items => _memory.ToArray();
     }
 }
index 166a204..90a9dec 100644 (file)
@@ -18,8 +18,8 @@ namespace System
     /// Represents a contiguous region of memory, similar to <see cref="ReadOnlySpan{T}"/>.
     /// Unlike <see cref="ReadOnlySpan{T}"/>, it is not a byref-like type.
     /// </summary>
-    [DebuggerDisplay("{DebuggerDisplay,nq}")]
     [DebuggerTypeProxy(typeof(MemoryDebugView<>))]
+    [DebuggerDisplay("{ToString(),raw}")]
     public readonly struct ReadOnlyMemory<T>
     {
         // NOTE: With the current implementation, Memory<T> and ReadOnlyMemory<T> must have the same layout,
@@ -97,9 +97,6 @@ namespace System
             _length = length;
         }
 
-        //Debugger Display = {T[length]}
-        private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length);
-
         /// <summary>
         /// Defines an implicit conversion of an array to a <see cref="ReadOnlyMemory{T}"/>
         /// </summary>
@@ -126,6 +123,19 @@ namespace System
         public bool IsEmpty => _length == 0;
 
         /// <summary>
+        /// For <see cref="ReadOnlyMemory{Char}"/>, returns a new instance of string that represents the characters pointed to by the memory.
+        /// Otherwise, returns a <see cref="string"/> with the name of the type and the number of elements.
+        /// </summary>
+        public override string ToString()
+        {
+            if (typeof(T) == typeof(char))
+            {
+                return (_object is string str) ? str.Substring(_index, _length) : Span.ToString();
+            }
+            return string.Format("System.ReadOnlyMemory<{0}>[{1}]", typeof(T).Name, _length);
+        }
+
+        /// <summary>
         /// Forms a slice out of the given memory, beginning at 'start'.
         /// </summary>
         /// <param name="start">The index at which to begin this slice.</param>