1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
2 
3 using System.Collections;
4 using System.Collections.Generic;
5 using System.Collections.ObjectModel;
6 using System.ComponentModel;
7 using System.Diagnostics.Contracts;
8 using System.Linq;
9 using System.Threading.Tasks;
10 using System.Web.Http.Controllers;
11 
12 namespace System.Web.Http.Internal
13 {
14     /// <summary>
15     /// A static class that provides various <see cref="Type"/> related helpers.
16     /// </summary>
17     internal static class TypeHelper
18     {
19         private static readonly Type TaskGenericType = typeof(Task<>);
20 
21         internal static readonly Type HttpControllerType = typeof(IHttpController);
22         internal static readonly Type ApiControllerType = typeof(ApiController);
23 
GetTaskInnerTypeOrNull(Type type)24         internal static Type GetTaskInnerTypeOrNull(Type type)
25         {
26             Contract.Assert(type != null);
27             if (type.IsGenericType && !type.IsGenericTypeDefinition)
28             {
29                 Type genericTypeDefinition = type.GetGenericTypeDefinition();
30                 // REVIEW: should we consider subclasses of Task<> ??
31                 if (TaskGenericType == genericTypeDefinition)
32                 {
33                     return type.GetGenericArguments()[0];
34                 }
35             }
36 
37             return null;
38         }
39 
ExtractGenericInterface(Type queryType, Type interfaceType)40         internal static Type ExtractGenericInterface(Type queryType, Type interfaceType)
41         {
42             Func<Type, bool> matchesInterface = t => t.IsGenericType && t.GetGenericTypeDefinition() == interfaceType;
43             return matchesInterface(queryType) ? queryType : queryType.GetInterfaces().FirstOrDefault(matchesInterface);
44         }
45 
GetTypeArgumentsIfMatch(Type closedType, Type matchingOpenType)46         internal static Type[] GetTypeArgumentsIfMatch(Type closedType, Type matchingOpenType)
47         {
48             if (!closedType.IsGenericType)
49             {
50                 return null;
51             }
52 
53             Type openType = closedType.GetGenericTypeDefinition();
54             return (matchingOpenType == openType) ? closedType.GetGenericArguments() : null;
55         }
56 
IsCompatibleObject(Type type, object value)57         internal static bool IsCompatibleObject(Type type, object value)
58         {
59             return (value == null && TypeAllowsNullValue(type)) || type.IsInstanceOfType(value);
60         }
61 
IsNullableValueType(Type type)62         internal static bool IsNullableValueType(Type type)
63         {
64             return Nullable.GetUnderlyingType(type) != null;
65         }
66 
TypeAllowsNullValue(Type type)67         internal static bool TypeAllowsNullValue(Type type)
68         {
69             return !type.IsValueType || IsNullableValueType(type);
70         }
71 
IsSimpleType(Type type)72         internal static bool IsSimpleType(Type type)
73         {
74             return type.IsPrimitive ||
75                    type.Equals(typeof(string)) ||
76                    type.Equals(typeof(DateTime)) ||
77                    type.Equals(typeof(Decimal)) ||
78                    type.Equals(typeof(Guid)) ||
79                    type.Equals(typeof(DateTimeOffset)) ||
80                    type.Equals(typeof(TimeSpan));
81         }
82 
IsSimpleUnderlyingType(Type type)83         internal static bool IsSimpleUnderlyingType(Type type)
84         {
85             Type underlyingType = Nullable.GetUnderlyingType(type);
86             if (underlyingType != null)
87             {
88                 type = underlyingType;
89             }
90 
91             return TypeHelper.IsSimpleType(type);
92         }
93 
HasStringConverter(Type type)94         internal static bool HasStringConverter(Type type)
95         {
96             return TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string));
97         }
98 
99         /// <summary>
100         /// Fast implementation to get the subset of a given type.
101         /// </summary>
102         /// <typeparam name="T">type to search for</typeparam>
103         /// <returns>subset of objects that can be assigned to T</returns>
104         internal static ReadOnlyCollection<T> OfType<T>(object[] objects) where T : class
105         {
106             int max = objects.Length;
107             List<T> list = new List<T>(max);
108             int idx = 0;
109             for (int i = 0; i < max; i++)
110             {
111                 T attr = objects[i] as T;
112                 if (attr != null)
113                 {
114                     list.Add(attr);
115                     idx++;
116                 }
117             }
118             list.Capacity = idx;
119 
120             return new ReadOnlyCollection<T>(list);
121         }
122     }
123 }
124