1 /* ****************************************************************************
\r
3 * Copyright (c) Microsoft Corporation. All rights reserved.
\r
5 * This software is subject to the Microsoft Public License (Ms-PL).
\r
6 * A copy of the license can be found in the license.htm file included
\r
7 * in this distribution.
\r
9 * You must not remove this notice, or any other, from this software.
\r
11 * ***************************************************************************/
\r
13 namespace System.Web.Mvc {
\r
15 using System.Collections;
\r
16 using System.Collections.Generic;
\r
18 using System.Reflection;
\r
19 using System.Threading;
\r
21 internal static class TypeHelpers {
\r
23 private static readonly Dictionary<Type, TryGetValueDelegate> _tryGetValueDelegateCache = new Dictionary<Type, TryGetValueDelegate>();
\r
24 private static readonly ReaderWriterLockSlim _tryGetValueDelegateCacheLock = new ReaderWriterLockSlim();
\r
26 private static readonly MethodInfo _strongTryGetValueImplInfo = typeof(TypeHelpers).GetMethod("StrongTryGetValueImpl", BindingFlags.NonPublic | BindingFlags.Static);
\r
28 public static readonly Assembly MsCorLibAssembly = typeof(string).Assembly;
\r
29 public static readonly Assembly MvcAssembly = typeof(Controller).Assembly;
\r
30 public static readonly Assembly SystemWebAssembly = typeof(HttpContext).Assembly;
\r
32 // method is used primarily for lighting up new .NET Framework features even if MVC targets the previous version
\r
33 // thisParameter is the 'this' parameter if target method is instance method, should be null for static method
\r
34 public static TDelegate CreateDelegate<TDelegate>(Assembly assembly, string typeName, string methodName, object thisParameter) where TDelegate : class {
\r
35 // ensure target type exists
\r
36 Type targetType = assembly.GetType(typeName, false /* throwOnError */);
\r
37 if (targetType == null) {
\r
41 return CreateDelegate<TDelegate>(targetType, methodName, thisParameter);
\r
44 public static TDelegate CreateDelegate<TDelegate>(Type targetType, string methodName, object thisParameter) where TDelegate : class {
\r
45 // ensure target method exists
\r
46 ParameterInfo[] delegateParameters = typeof(TDelegate).GetMethod("Invoke").GetParameters();
\r
47 Type[] argumentTypes = Array.ConvertAll(delegateParameters, pInfo => pInfo.ParameterType);
\r
48 MethodInfo targetMethod = targetType.GetMethod(methodName, argumentTypes);
\r
49 if (targetMethod == null) {
\r
53 TDelegate d = Delegate.CreateDelegate(typeof(TDelegate), thisParameter, targetMethod, false /* throwOnBindFailure */) as TDelegate;
\r
57 public static TryGetValueDelegate CreateTryGetValueDelegate(Type targetType) {
\r
58 TryGetValueDelegate result;
\r
60 _tryGetValueDelegateCacheLock.EnterReadLock();
\r
62 if (_tryGetValueDelegateCache.TryGetValue(targetType, out result)) {
\r
67 _tryGetValueDelegateCacheLock.ExitReadLock();
\r
70 Type dictionaryType = ExtractGenericInterface(targetType, typeof(IDictionary<,>));
\r
72 // just wrap a call to the underlying IDictionary<TKey, TValue>.TryGetValue() where string can be cast to TKey
\r
73 if (dictionaryType != null) {
\r
74 Type[] typeArguments = dictionaryType.GetGenericArguments();
\r
75 Type keyType = typeArguments[0];
\r
76 Type returnType = typeArguments[1];
\r
78 if (keyType.IsAssignableFrom(typeof(string))) {
\r
79 MethodInfo strongImplInfo = _strongTryGetValueImplInfo.MakeGenericMethod(keyType, returnType);
\r
80 result = (TryGetValueDelegate)Delegate.CreateDelegate(typeof(TryGetValueDelegate), strongImplInfo);
\r
84 // wrap a call to the underlying IDictionary.Item()
\r
85 if (result == null && typeof(IDictionary).IsAssignableFrom(targetType)) {
\r
86 result = TryGetValueFromNonGenericDictionary;
\r
89 _tryGetValueDelegateCacheLock.EnterWriteLock();
\r
91 _tryGetValueDelegateCache[targetType] = result;
\r
94 _tryGetValueDelegateCacheLock.ExitWriteLock();
\r
100 public static Type ExtractGenericInterface(Type queryType, Type interfaceType) {
\r
101 Func<Type, bool> matchesInterface = t => t.IsGenericType && t.GetGenericTypeDefinition() == interfaceType;
\r
102 return (matchesInterface(queryType)) ? queryType : queryType.GetInterfaces().FirstOrDefault(matchesInterface);
\r
105 public static object GetDefaultValue(Type type) {
\r
106 return (TypeAllowsNullValue(type)) ? null : Activator.CreateInstance(type);
\r
109 public static bool IsCompatibleObject<T>(object value) {
\r
110 return (value is T || (value == null && TypeAllowsNullValue(typeof(T))));
\r
113 public static bool IsNullableValueType(Type type) {
\r
114 return Nullable.GetUnderlyingType(type) != null;
\r
117 private static bool StrongTryGetValueImpl<TKey, TValue>(object dictionary, string key, out object value) {
\r
118 IDictionary<TKey, TValue> strongDict = (IDictionary<TKey, TValue>)dictionary;
\r
120 TValue strongValue;
\r
121 bool retVal = strongDict.TryGetValue((TKey)(object)key, out strongValue);
\r
122 value = strongValue;
\r
126 private static bool TryGetValueFromNonGenericDictionary(object dictionary, string key, out object value) {
\r
127 IDictionary weakDict = (IDictionary)dictionary;
\r
129 bool containsKey = weakDict.Contains(key);
\r
130 value = (containsKey) ? weakDict[key] : null;
\r
131 return containsKey;
\r
134 public static bool TypeAllowsNullValue(Type type) {
\r
135 return (!type.IsValueType || IsNullableValueType(type));
\r