Skip to content

Commit 7c090e7

Browse files
committed
Added support for pointer and by-ref types
1 parent 15f90f3 commit 7c090e7

File tree

2 files changed

+61
-4
lines changed

2 files changed

+61
-4
lines changed

Microsoft.Toolkit/Extensions/TypeExtensions.cs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,34 @@ static string FormatDisplayString(Type type, int genericTypeOffset, ReadOnlySpan
154154
}
155155

156156
// Atomically get or build the display string for the current type.
157-
// Manually create a static lambda here to enable caching of the generated closure.
158-
// This is a workaround for the missing caching for method group conversions, and should
159-
// be removed once this issue is resolved: https://github.com/dotnet/roslyn/issues/5835.
160-
return DisplayNames.GetValue(type, t => FormatDisplayString(t, 0, type.GetGenericArguments()));
157+
return DisplayNames.GetValue(type, t =>
158+
{
159+
// By-ref types are displayed as T&
160+
if (t.IsByRef)
161+
{
162+
t = t.GetElementType();
163+
164+
return $"{FormatDisplayString(t, 0, type.GetGenericArguments())}&";
165+
}
166+
167+
// Pointer types are displayed as T*
168+
if (t.IsPointer)
169+
{
170+
int depth = 0;
171+
172+
// Calculate the pointer indirection level
173+
while (t.IsPointer)
174+
{
175+
depth++;
176+
t = t.GetElementType();
177+
}
178+
179+
return $"{FormatDisplayString(t, 0, type.GetGenericArguments())}{new string('*', depth)}";
180+
}
181+
182+
// Standard path for concrete types
183+
return FormatDisplayString(t, 0, type.GetGenericArguments());
184+
});
161185
}
162186

163187
/// <summary>

UnitTests/UnitTests.Shared/Extensions/Test_TypeExtensions.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,39 @@ public void Test_TypeExtensions_NestedTypes(string name, Type type)
7373
Assert.AreEqual(name, type.ToTypeString());
7474
}
7575

76+
#pragma warning disable SA1015 // Closing generic brackets should be spaced correctly
77+
[TestCategory("TypeExtensions")]
78+
[TestMethod]
79+
[DataRow("void*", typeof(void*))]
80+
[DataRow("int**", typeof(int**))]
81+
[DataRow("byte***", typeof(byte***))]
82+
[DataRow("System.Guid*", typeof(Guid*))]
83+
[DataRow("UnitTests.Extensions.Foo<int>*", typeof(Foo<int>*))]
84+
[DataRow("UnitTests.Extensions.Test_TypeExtensions.Animal.Cat**", typeof(Animal.Cat**))]
85+
[DataRow("UnitTests.Extensions.Test_TypeExtensions.Animal.Cat<int>*", typeof(Animal.Cat<int>*))]
86+
[DataRow("UnitTests.Extensions.Test_TypeExtensions.Animal.Cat<float>.Bar**", typeof(Animal.Cat<float>.Bar**))]
87+
[DataRow("UnitTests.Extensions.Test_TypeExtensions.Animal.Cat<double>.Bar<int>***", typeof(Animal.Cat<double>.Bar<int>***))]
88+
public void Test_TypeExtensions_PointerTypes(string name, Type type)
89+
{
90+
Assert.AreEqual(name, type.ToTypeString());
91+
}
92+
#pragma warning restore SA1015
93+
94+
[TestCategory("TypeExtensions")]
95+
[TestMethod]
96+
[DataRow("int&", typeof(int))]
97+
[DataRow("byte&", typeof(byte))]
98+
[DataRow("System.Guid&", typeof(Guid))]
99+
[DataRow("UnitTests.Extensions.Foo<int>&", typeof(Foo<int>))]
100+
[DataRow("UnitTests.Extensions.Test_TypeExtensions.Animal.Cat&", typeof(Animal.Cat))]
101+
[DataRow("UnitTests.Extensions.Test_TypeExtensions.Animal.Cat<int>&", typeof(Animal.Cat<int>))]
102+
[DataRow("UnitTests.Extensions.Test_TypeExtensions.Animal.Cat<float>.Bar&", typeof(Animal.Cat<float>.Bar))]
103+
[DataRow("UnitTests.Extensions.Test_TypeExtensions.Animal.Cat<double>.Bar<int>&", typeof(Animal.Cat<double>.Bar<int>))]
104+
public void Test_TypeExtensions_RefTypes(string name, Type type)
105+
{
106+
Assert.AreEqual(name, type.MakeByRefType().ToTypeString());
107+
}
108+
76109
private class Animal
77110
{
78111
public struct Cat

0 commit comments

Comments
 (0)