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