Skip to content

Commit a6303cd

Browse files
authored
Update type extension methods to detect arrays and dictionaries better (#247)
1 parent 2f3fbf6 commit a6303cd

File tree

2 files changed

+76
-93
lines changed

2 files changed

+76
-93
lines changed

src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Extensions/TypeExtensions.cs

Lines changed: 28 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ public static bool IsReferentialType(this Type type)
107107
return isReferential;
108108
}
109109

110+
private static HashSet<Type> jObjects = new HashSet<Type>
111+
{
112+
typeof(JObject),
113+
typeof(JToken),
114+
typeof(JArray),
115+
};
116+
110117
/// <summary>
111118
/// Checks whether the given type is Json.NET related <see cref="JObject"/>, <see cref="JToken"/> or not.
112119
/// </summary>
@@ -119,12 +126,7 @@ public static bool IsJObjectType(this Type type)
119126
return false;
120127
}
121128

122-
if (type == typeof(JObject))
123-
{
124-
return true;
125-
}
126-
127-
if (type == typeof(JToken))
129+
if (jObjects.Any(p => p == type))
128130
{
129131
return true;
130132
}
@@ -657,82 +659,31 @@ public static bool HasInterface(this Type type, string interfaceName)
657659

658660
private static bool IsArrayType(this Type type)
659661
{
660-
if (type.BaseType == typeof(Array))
661-
{
662-
return true;
663-
}
664-
665-
if (type.IsGenericTypeOf(typeof(List<>)))
666-
{
667-
return true;
668-
}
669-
670-
if (type.IsGenericTypeOf(typeof(IList<>)))
671-
{
672-
return true;
673-
}
674-
675-
if (type.IsGenericTypeOf(typeof(ICollection<>)))
676-
{
677-
return true;
678-
}
679-
680-
if (type.IsGenericTypeOf(typeof(IEnumerable<>)))
681-
{
682-
return true;
683-
}
684-
685-
if (type.IsGenericTypeOf(typeof(IReadOnlyList<>)))
686-
{
687-
return true;
688-
}
689-
690-
if (type.IsGenericTypeOf(typeof(IReadOnlyCollection<>)))
691-
{
692-
return true;
693-
}
694-
695-
if (type.IsGenericTypeOf(typeof(HashSet<>)))
696-
{
697-
return true;
698-
}
699-
700-
if (type.IsGenericTypeOf(typeof(ISet<>)))
701-
{
702-
return true;
703-
}
704-
705-
return false;
662+
var isArrayType = type.Name.Equals("String", StringComparison.InvariantCultureIgnoreCase) == false &&
663+
type.GetInterfaces()
664+
.Where(p => p.IsInterface)
665+
.Where(p => p.Name.Equals("IEnumerable", StringComparison.InvariantCultureIgnoreCase) == true)
666+
.Any() &&
667+
type.IsJObjectType() == false &&
668+
type.IsDictionaryType() == false;
669+
670+
return isArrayType;
706671
}
707672

708-
private static bool IsDictionaryType(this Type type)
673+
private static HashSet<string> dictionaries = new HashSet<string>
709674
{
710-
if (!type.IsGenericType)
711-
{
712-
return false;
713-
}
675+
"Dictionary`2",
676+
"IDictionary`2",
677+
"IReadOnlyDictionary`2",
678+
"KeyValuePair`2",
679+
};
714680

715-
if (type.Name.Equals("Dictionary`2", StringComparison.CurrentCultureIgnoreCase))
716-
{
717-
return true;
718-
}
719-
720-
if (type.Name.Equals("IDictionary`2", StringComparison.CurrentCultureIgnoreCase))
721-
{
722-
return true;
723-
}
724-
725-
if (type.Name.Equals("IReadOnlyDictionary`2", StringComparison.CurrentCultureIgnoreCase))
726-
{
727-
return true;
728-
}
729-
730-
if (type.Name.Equals("KeyValuePair`2", StringComparison.CurrentCultureIgnoreCase))
731-
{
732-
return true;
733-
}
681+
private static bool IsDictionaryType(this Type type)
682+
{
683+
var isDictionaryType = type.IsGenericType &&
684+
dictionaries.Any(p => type.Name.Equals(p, StringComparison.InvariantCultureIgnoreCase) == true);
734685

735-
return false;
686+
return isDictionaryType;
736687
}
737688

738689
private static bool IsNullableType(this Type type, out Type underlyingType)

test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Extensions/TypeExtensionsTests.cs

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,57 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests.Extensions
1818
[TestClass]
1919
public class TypeExtensionsTests
2020
{
21-
[TestMethod]
22-
public void Given_IList_Should_Return_True() =>
23-
typeof(IList<string>).IsOpenApiArray().Should().BeTrue();
24-
25-
[TestMethod]
26-
public void Given_List_Should_Return_True() =>
27-
typeof(List<string>).IsOpenApiArray().Should().BeTrue();
21+
[DataTestMethod]
22+
[DataRow(typeof(string), false)]
23+
[DataRow(typeof(int), false)]
24+
[DataRow(typeof(double), false)]
25+
[DataRow(typeof(bool), false)]
26+
[DataRow(typeof(Array), true)]
27+
[DataRow(typeof(string[]), true)]
28+
[DataRow(typeof(List<string>), true)]
29+
[DataRow(typeof(IList<string>), true)]
30+
[DataRow(typeof(ICollection<string>), true)]
31+
[DataRow(typeof(IEnumerable<string>), true)]
32+
[DataRow(typeof(IReadOnlyList<string>), true)]
33+
[DataRow(typeof(IReadOnlyCollection<string>), true)]
34+
[DataRow(typeof(HashSet<string>), true)]
35+
[DataRow(typeof(ISet<string>), true)]
36+
[DataRow(typeof(Dictionary<string, string>), false)]
37+
[DataRow(typeof(IDictionary<string, string>), false)]
38+
[DataRow(typeof(IReadOnlyDictionary<string, string>), false)]
39+
[DataRow(typeof(KeyValuePair<string, string>), false)]
40+
public void Given_ArrayTypes_When_IsOpenApiArray_Invoked_Then_It_Should_Return_Result(Type type, bool expected)
41+
{
42+
var result = TypeExtensions.IsOpenApiArray(type);
2843

29-
[TestMethod]
30-
public void Given_Array_Method_Should_Return_True() =>
31-
typeof(string[]).IsOpenApiArray().Should().BeTrue();
44+
result.Should().Be(expected);
45+
}
3246

33-
[TestMethod]
34-
public void Given_Object_That_Extends_List_Should_Return_False() =>
35-
typeof(JObject).IsOpenApiArray().Should().BeFalse();
47+
[DataTestMethod]
48+
[DataRow(typeof(string), false)]
49+
[DataRow(typeof(int), false)]
50+
[DataRow(typeof(double), false)]
51+
[DataRow(typeof(bool), false)]
52+
[DataRow(typeof(Array), false)]
53+
[DataRow(typeof(string[]), false)]
54+
[DataRow(typeof(List<string>), false)]
55+
[DataRow(typeof(IList<string>), false)]
56+
[DataRow(typeof(ICollection<string>), false)]
57+
[DataRow(typeof(IEnumerable<string>), false)]
58+
[DataRow(typeof(IReadOnlyList<string>), false)]
59+
[DataRow(typeof(IReadOnlyCollection<string>), false)]
60+
[DataRow(typeof(HashSet<string>), false)]
61+
[DataRow(typeof(ISet<string>), false)]
62+
[DataRow(typeof(Dictionary<string, string>), true)]
63+
[DataRow(typeof(IDictionary<string, string>), true)]
64+
[DataRow(typeof(IReadOnlyDictionary<string, string>), true)]
65+
[DataRow(typeof(KeyValuePair<string, string>), true)]
66+
public void Given_DictionaryTypes_When_IsOpenApiDictionary_Invoked_Then_It_Should_Return_Result(Type type, bool expected)
67+
{
68+
var result = TypeExtensions.IsOpenApiDictionary(type);
3669

37-
[TestMethod]
38-
public void Given_String_Method_Should_Return_False() =>
39-
typeof(string).IsOpenApiArray().Should().BeFalse();
70+
result.Should().Be(expected);
71+
}
4072

4173
[TestMethod]
4274
public void Given_DefaultNamingStrategy_When_GetOpenApiTypeName_Invoked_Then_It_Should_Return_Result()

0 commit comments

Comments
 (0)