Skip to content

Commit 6ed2eb4

Browse files
committed
Creating friendly names for anonymous types
1 parent a398092 commit 6ed2eb4

File tree

4 files changed

+114
-69
lines changed

4 files changed

+114
-69
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
namespace AgileObjects.ReadableExpressions.UnitTests.Extensions
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq.Expressions;
6+
using Microsoft.VisualStudio.TestTools.UnitTesting;
7+
using ReadableExpressions.Extensions;
8+
9+
[TestClass]
10+
public class WhenGettingFriendlyNames
11+
{
12+
[TestMethod]
13+
public void ShouldUseFriendlyNamesForArrays()
14+
{
15+
var intArrayVariable = Expression.Variable(typeof(int[]), "ints");
16+
var assignNull = Expression.Assign(intArrayVariable, Expression.Default(intArrayVariable.Type));
17+
var assignNullBlock = Expression.Block(new[] { intArrayVariable }, assignNull);
18+
19+
var translated = assignNullBlock.ToReadableString();
20+
21+
Assert.AreEqual("var ints = default(int[]);", translated);
22+
}
23+
24+
[TestMethod]
25+
public void ShouldUseFriendlyNamesForCharacters()
26+
{
27+
Expression<Func<char, double>> characterToNumeric = c => char.GetNumericValue(c);
28+
29+
var translated = characterToNumeric.ToReadableString();
30+
31+
Assert.AreEqual("c => char.GetNumericValue(c)", translated);
32+
}
33+
34+
[TestMethod]
35+
public void ShouldUseFriendlyNamesForAnonymousTypes()
36+
{
37+
var anon = new { One = 1, Two = "two" };
38+
39+
var friendlyName = anon.GetType().GetFriendlyName();
40+
41+
Assert.AreEqual("AnonymousType<int, string>", friendlyName);
42+
}
43+
44+
// See https://github.com/agileobjects/ReadableExpressions/issues/6
45+
[TestMethod]
46+
public void ShouldUseFriendlyNamesForMultiplyNestedTypes()
47+
{
48+
var nestedType = Expression.Constant(typeof(OuterClass.InnerClass.Nested), typeof(Type));
49+
50+
var translated = nestedType.ToReadableString();
51+
52+
Assert.AreEqual("typeof(OuterClass.InnerClass.Nested)", translated);
53+
}
54+
55+
[TestMethod]
56+
public void ShouldUseFriendlyNamesForListsOfNestedTypes()
57+
{
58+
var newNestedTypeList = Expression.New(typeof(List<>).MakeGenericType(typeof(OuterClass.InnerClass)));
59+
60+
var translated = newNestedTypeList.ToReadableString();
61+
62+
Assert.AreEqual("new List<OuterClass.InnerClass>()", translated);
63+
}
64+
65+
[TestMethod]
66+
public void ShouldUseFriendlyNamesForGenericNestedTypes()
67+
{
68+
var genericListEnumeratorType = Expression.Constant(typeof(List<string>.Enumerator), typeof(Type));
69+
70+
var translated = genericListEnumeratorType.ToReadableString();
71+
72+
Assert.AreEqual("typeof(List<string>.Enumerator)", translated);
73+
}
74+
75+
[TestMethod]
76+
public void ShouldUseFriendlyNamesForGenericMultiplyNestedTypes()
77+
{
78+
var nestedGenericType = Expression.Constant(
79+
typeof(OuterGeneric<int>.InnerGeneric<long>.Nested),
80+
typeof(Type));
81+
82+
var translated = nestedGenericType.ToReadableString();
83+
84+
Assert.AreEqual("typeof(OuterGeneric<int>.InnerGeneric<long>.Nested)", translated);
85+
}
86+
}
87+
}

ReadableExpressions.UnitTests/ReadableExpressions.UnitTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
<Link>VersionInfo.cs</Link>
6262
</Compile>
6363
<Compile Include="Extensions\WhenGettingAParentExpressionNode.cs" />
64+
<Compile Include="Extensions\WhenGettingFriendlyNames.cs" />
6465
<Compile Include="WhenUsingPartialTrust.cs" />
6566
<Compile Include="WhenTranslatingStringConcatenation.cs" />
6667
<Compile Include="WhenTranslatingComments.cs" />

ReadableExpressions.UnitTests/WhenFormattingCode.cs

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -675,71 +675,6 @@ public void ShouldSplitLongChainedMethodsOntoMultipleLines()
675675
Assert.AreEqual(EXPECTED.TrimStart(), translated);
676676
}
677677

678-
[TestMethod]
679-
public void ShouldUseFriendlyNamesForArrays()
680-
{
681-
var intArrayVariable = Expression.Variable(typeof(int[]), "ints");
682-
var assignNull = Expression.Assign(intArrayVariable, Expression.Default(intArrayVariable.Type));
683-
var assignNullBlock = Expression.Block(new[] { intArrayVariable }, assignNull);
684-
685-
var translated = assignNullBlock.ToReadableString();
686-
687-
Assert.AreEqual("var ints = default(int[]);", translated);
688-
}
689-
690-
[TestMethod]
691-
public void ShouldUseFriendlyNamesForCharacters()
692-
{
693-
Expression<Func<char, double>> characterToNumeric = c => char.GetNumericValue(c);
694-
695-
var translated = characterToNumeric.ToReadableString();
696-
697-
Assert.AreEqual("c => char.GetNumericValue(c)", translated);
698-
}
699-
700-
// See https://github.com/agileobjects/ReadableExpressions/issues/6
701-
[TestMethod]
702-
public void ShouldUseFriendlyNamesForMultiplyNestedTypes()
703-
{
704-
var nestedType = Expression.Constant(typeof(OuterClass.InnerClass.Nested), typeof(Type));
705-
706-
var translated = nestedType.ToReadableString();
707-
708-
Assert.AreEqual("typeof(OuterClass.InnerClass.Nested)", translated);
709-
}
710-
711-
[TestMethod]
712-
public void ShouldUseFriendlyNamesForListsOfNestedTypes()
713-
{
714-
var newNestedTypeList = Expression.New(typeof(List<>).MakeGenericType(typeof(OuterClass.InnerClass)));
715-
716-
var translated = newNestedTypeList.ToReadableString();
717-
718-
Assert.AreEqual("new List<OuterClass.InnerClass>()", translated);
719-
}
720-
721-
[TestMethod]
722-
public void ShouldUseFriendlyNamesForGenericNestedTypes()
723-
{
724-
var genericListEnumeratorType = Expression.Constant(typeof(List<string>.Enumerator), typeof(Type));
725-
726-
var translated = genericListEnumeratorType.ToReadableString();
727-
728-
Assert.AreEqual("typeof(List<string>.Enumerator)", translated);
729-
}
730-
731-
[TestMethod]
732-
public void ShouldUseFriendlyNamesForGenericMultiplyNestedTypes()
733-
{
734-
var nestedGenericType = Expression.Constant(
735-
typeof(OuterGeneric<int>.InnerGeneric<long>.Nested),
736-
typeof(Type));
737-
738-
var translated = nestedGenericType.ToReadableString();
739-
740-
Assert.AreEqual("typeof(OuterGeneric<int>.InnerGeneric<long>.Nested)", translated);
741-
}
742-
743678
[TestMethod]
744679
public void ShouldTranslateNullToNull()
745680
{

ReadableExpressions/Extensions/PublicTypeExtensions.cs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,37 @@ private static string GetGenericTypeName(Type genericType)
114114
return genericTypeName;
115115
}
116116

117-
private static string GetGenericTypeName(string typeName, int numberOfParameters, IEnumerable<Type> typeArguments)
117+
private static string GetGenericTypeName(
118+
string typeName,
119+
int numberOfParameters,
120+
IEnumerable<Type> typeArguments)
118121
{
119122
var typeGenericTypeArgumentFriendlyNames =
120-
string.Join(", ", typeArguments.Select(tp => GetFriendlyName(tp)));
123+
string.Join(", ", typeArguments.Select(GetFriendlyName));
121124

122125
typeName = typeName.Replace(
123126
"`" + numberOfParameters,
124127
"<" + typeGenericTypeArgumentFriendlyNames + ">");
125128

129+
return typeName.StartsWith('<') ? GetAnonymousTypeName(typeName) : typeName;
130+
}
131+
132+
private static string GetAnonymousTypeName(string typeName)
133+
{
134+
var anonTypeIndex = typeName.IndexOf("AnonymousType", StringComparison.Ordinal);
135+
136+
if (anonTypeIndex == -1)
137+
{
138+
return typeName;
139+
}
140+
141+
typeName = typeName.Substring(anonTypeIndex);
142+
143+
var trimStartIndex = "AnonymousType".Length;
144+
var argumentsStartIndex = typeName.IndexOf('<');
145+
146+
typeName = typeName.Remove(trimStartIndex, argumentsStartIndex - trimStartIndex);
147+
126148
return typeName;
127149
}
128150

@@ -137,10 +159,10 @@ public static bool CanBeNull(this Type type)
137159
}
138160

139161
/// <summary>
140-
/// Returns a value indicating if the given <paramref name="type"/> is a Nullable&lt;T&gt;.
162+
/// Returns a value indicating if the given <paramref name="type"/> is a Nullable{T}.
141163
/// </summary>
142164
/// <param name="type">The type for which to make the determination.</param>
143-
/// <returns>True if the given <paramref name="type"/> is a Nullable&lt;T&gt;, otherwise false.</returns>
165+
/// <returns>True if the given <paramref name="type"/> is a Nullable{T}, otherwise false.</returns>
144166
public static bool IsNullableType(this Type type)
145167
{
146168
return Nullable.GetUnderlyingType(type) != null;

0 commit comments

Comments
 (0)