-
Notifications
You must be signed in to change notification settings - Fork 494
/
TypeSystem.cs
156 lines (133 loc) · 5.58 KB
/
TypeSystem.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Azure.Cosmos.Linq
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
internal static class TypeSystem
{
public static Type GetElementType(Type type)
{
return GetElementType(type, new HashSet<Type>());
}
public static string GetMemberName(this MemberInfo memberInfo)
{
// Json.Net honors JsonPropertyAttribute more than DataMemberAttribute
// So we check for JsonPropertyAttribute first.
JsonPropertyAttribute jsonPropertyAttribute = memberInfo.GetCustomAttribute<JsonPropertyAttribute>(true);
if (jsonPropertyAttribute != null && !string.IsNullOrEmpty(jsonPropertyAttribute.PropertyName))
{
return jsonPropertyAttribute.PropertyName;
}
DataContractAttribute dataContractAttribute = memberInfo.DeclaringType.GetCustomAttribute<DataContractAttribute>(true);
if (dataContractAttribute != null)
{
DataMemberAttribute dataMemberAttribute = memberInfo.GetCustomAttribute<DataMemberAttribute>(true);
if (dataMemberAttribute != null && !string.IsNullOrEmpty(dataMemberAttribute.Name))
{
return dataMemberAttribute.Name;
}
}
return memberInfo.Name;
}
private static Type GetElementType(Type type, HashSet<Type> visitedSet)
{
Debug.Assert(type != null);
Debug.Assert(visitedSet != null);
// Check if we visited the type, to prevent exponential recursion in case multi-inheritance.
if (visitedSet.Contains(type))
{
return null;
}
// Mark type as visited.
visitedSet.Add(type);
// Check if type is array.
if (type.IsArray)
{
return type.GetElementType();
}
// Attempt to find most specific element type among base class and all implemented interfaces.
Type elementType = null;
// Check if type is intance of generic IEnumerable<>
if (type.IsInterface() && type.IsGenericType() && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
elementType = GetMoreSpecificType(elementType, type.GetGenericArguments()[0]);
}
foreach (Type interfaceType in type.GetInterfaces())
{
elementType = GetMoreSpecificType(elementType, GetElementType(interfaceType, visitedSet));
}
if (type.GetBaseType() != null && type.GetBaseType() != typeof(object))
{
elementType = GetMoreSpecificType(elementType, GetElementType(type.GetBaseType(), visitedSet));
}
return elementType;
}
private static Type GetMoreSpecificType(Type left, Type right)
{
if (left != null && right != null)
{
// Prefer left type over right type, in case both are assignable from each other or none.
if (right.IsAssignableFrom(left))
{
return left;
}
else if (left.IsAssignableFrom(right))
{
return right;
}
else
{
return left;
}
}
else
{
return left ?? right;
}
}
/// <summary>
/// True if type is anonymous.
/// </summary>
/// <param name="type">Type to check.</param>
/// <returns>Trye if the type is anonymous.</returns>
public static Boolean IsAnonymousType(this Type type)
{
Boolean hasCompilerGeneratedAttribute = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any();
Boolean nameContainsAnonymousType = type.FullName.Contains("AnonymousType");
Boolean isAnonymousType = hasCompilerGeneratedAttribute && nameContainsAnonymousType;
return isAnonymousType;
}
public static bool IsEnumerable(this Type type)
{
if (type == typeof(Enumerable)) return true;
if (type.IsGenericType() && type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) return true;
IEnumerable<Type> types = type.GetInterfaces().Where(interfaceType => interfaceType.IsGenericType() && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>));
return (types.FirstOrDefault() != null);
}
public static bool IsExtensionMethod(this MethodInfo methodInfo)
{
return methodInfo.GetCustomAttribute(typeof(ExtensionAttribute)) != null;
}
public static bool IsNullable(this Type type)
{
return type.IsGenericType() && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
public static Type NullableUnderlyingType(this Type type)
{
if (type.IsNullable())
{
return type.GetGenericArguments()[0];
}
return type;
}
}
}