Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[mono.git] / mcs / class / System.Web.Mvc2 / System.Web.Mvc / TypeHelpers.cs
1 /* ****************************************************************************\r
2  *\r
3  * Copyright (c) Microsoft Corporation. All rights reserved.\r
4  *\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
8  *\r
9  * You must not remove this notice, or any other, from this software.\r
10  *\r
11  * ***************************************************************************/\r
12 \r
13 namespace System.Web.Mvc {\r
14     using System;\r
15     using System.Collections;\r
16     using System.Collections.Generic;\r
17     using System.Linq;\r
18     using System.Reflection;\r
19     using System.Threading;\r
20 \r
21     internal static class TypeHelpers {\r
22 \r
23         private static readonly Dictionary<Type, TryGetValueDelegate> _tryGetValueDelegateCache = new Dictionary<Type, TryGetValueDelegate>();\r
24         private static readonly ReaderWriterLockSlim _tryGetValueDelegateCacheLock = new ReaderWriterLockSlim();\r
25 \r
26         private static readonly MethodInfo _strongTryGetValueImplInfo = typeof(TypeHelpers).GetMethod("StrongTryGetValueImpl", BindingFlags.NonPublic | BindingFlags.Static);\r
27 \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
31 \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
38                 return null;\r
39             }\r
40 \r
41             return CreateDelegate<TDelegate>(targetType, methodName, thisParameter);\r
42         }\r
43 \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
50                 return null;\r
51             }\r
52 \r
53             TDelegate d = Delegate.CreateDelegate(typeof(TDelegate), thisParameter, targetMethod, false /* throwOnBindFailure */) as TDelegate;\r
54             return d;\r
55         }\r
56 \r
57         public static TryGetValueDelegate CreateTryGetValueDelegate(Type targetType) {\r
58             TryGetValueDelegate result;\r
59 \r
60             _tryGetValueDelegateCacheLock.EnterReadLock();\r
61             try {\r
62                 if (_tryGetValueDelegateCache.TryGetValue(targetType, out result)) {\r
63                     return result;\r
64                 }\r
65             }\r
66             finally {\r
67                 _tryGetValueDelegateCacheLock.ExitReadLock();\r
68             }\r
69 \r
70             Type dictionaryType = ExtractGenericInterface(targetType, typeof(IDictionary<,>));\r
71 \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
77 \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
81                 }\r
82             }\r
83 \r
84             // wrap a call to the underlying IDictionary.Item()\r
85             if (result == null && typeof(IDictionary).IsAssignableFrom(targetType)) {\r
86                 result = TryGetValueFromNonGenericDictionary;\r
87             }\r
88 \r
89             _tryGetValueDelegateCacheLock.EnterWriteLock();\r
90             try {\r
91                 _tryGetValueDelegateCache[targetType] = result;\r
92             }\r
93             finally {\r
94                 _tryGetValueDelegateCacheLock.ExitWriteLock();\r
95             }\r
96 \r
97             return result;\r
98         }\r
99 \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
103         }\r
104 \r
105         public static object GetDefaultValue(Type type) {\r
106             return (TypeAllowsNullValue(type)) ? null : Activator.CreateInstance(type);\r
107         }\r
108 \r
109         public static bool IsCompatibleObject<T>(object value) {\r
110             return (value is T || (value == null && TypeAllowsNullValue(typeof(T))));\r
111         }\r
112 \r
113         public static bool IsNullableValueType(Type type) {\r
114             return Nullable.GetUnderlyingType(type) != null;\r
115         }\r
116 \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
119 \r
120             TValue strongValue;\r
121             bool retVal = strongDict.TryGetValue((TKey)(object)key, out strongValue);\r
122             value = strongValue;\r
123             return retVal;\r
124         }\r
125 \r
126         private static bool TryGetValueFromNonGenericDictionary(object dictionary, string key, out object value) {\r
127             IDictionary weakDict = (IDictionary)dictionary;\r
128 \r
129             bool containsKey = weakDict.Contains(key);\r
130             value = (containsKey) ? weakDict[key] : null;\r
131             return containsKey;\r
132         }\r
133 \r
134         public static bool TypeAllowsNullValue(Type type) {\r
135             return (!type.IsValueType || IsNullableValueType(type));\r
136         }\r
137     }\r
138 }\r