PageRenderTime 61ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 1ms

/DLR_Main/Runtime/Microsoft.Dynamic/Runtime/ReflectionCache.cs

https://bitbucket.org/mdavid/dlr
C# | 203 lines | 147 code | 26 blank | 30 comment | 35 complexity | c763def4577b2435d9305065d9fb0773 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Reflection;
  18. using Microsoft.Scripting.Utils;
  19. using Microsoft.Contracts;
  20. using Microsoft.Scripting.Actions;
  21. namespace Microsoft.Scripting.Runtime {
  22. /// <summary>
  23. /// Provides a cache of reflection members. Only one set of values is ever handed out per a
  24. /// specific request.
  25. /// </summary>
  26. public static class ReflectionCache {
  27. private static readonly Dictionary<MethodBaseCache, MethodGroup> _functions = new Dictionary<MethodBaseCache, MethodGroup>();
  28. private static readonly Dictionary<Type, TypeTracker> _typeCache = new Dictionary<Type, TypeTracker>();
  29. public static MethodGroup GetMethodGroup(Type type, string name) {
  30. return GetMethodGroup(type, name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.InvokeMethod, null);
  31. }
  32. /// <summary>
  33. /// Gets a singleton method group from the provided type.
  34. ///
  35. /// The provided method group will be unique based upon the methods defined, not based upon the type/name
  36. /// combination. In other words calling GetMethodGroup on a base type and a derived type that introduces
  37. /// no new methods under a given name will result in the same method group for both types.
  38. /// </summary>
  39. public static MethodGroup GetMethodGroup(Type type, string name, BindingFlags bindingFlags, MemberFilter filter) {
  40. ContractUtils.RequiresNotNull(type, "type");
  41. ContractUtils.RequiresNotNull(name, "name");
  42. MemberInfo[] mems = type.FindMembers(MemberTypes.Method,
  43. bindingFlags,
  44. filter ?? delegate(MemberInfo mem, object filterCritera) {
  45. return mem.Name == name;
  46. },
  47. null);
  48. MethodGroup res = null;
  49. if (mems.Length != 0) {
  50. MethodInfo[] methods = ArrayUtils.ConvertAll<MemberInfo, MethodInfo>(
  51. mems,
  52. delegate(MemberInfo x) { return (MethodInfo)x; }
  53. );
  54. res = GetMethodGroup(name, methods);
  55. }
  56. return res;
  57. }
  58. public static MethodGroup GetMethodGroup(string name, MethodBase[] methods) {
  59. MethodGroup res = null;
  60. MethodBaseCache cache = new MethodBaseCache(name, methods);
  61. lock (_functions) {
  62. if (!_functions.TryGetValue(cache, out res)) {
  63. _functions[cache] = res = new MethodGroup(
  64. ArrayUtils.ConvertAll<MethodBase, MethodTracker>(
  65. methods,
  66. delegate(MethodBase x) {
  67. return (MethodTracker)MemberTracker.FromMemberInfo(x);
  68. }
  69. )
  70. );
  71. }
  72. }
  73. return res;
  74. }
  75. public static MethodGroup GetMethodGroup(string name, MemberGroup mems) {
  76. MethodGroup res = null;
  77. MethodBase[] bases = new MethodBase[mems.Count];
  78. MethodTracker[] trackers = new MethodTracker[mems.Count];
  79. for (int i = 0; i < bases.Length; i++) {
  80. trackers[i] = (MethodTracker)mems[i];
  81. bases[i] = trackers[i].Method;
  82. }
  83. if (mems.Count != 0) {
  84. MethodBaseCache cache = new MethodBaseCache(name, bases);
  85. lock (_functions) {
  86. if (!_functions.TryGetValue(cache, out res)) {
  87. _functions[cache] = res = new MethodGroup(trackers);
  88. }
  89. }
  90. }
  91. return res;
  92. }
  93. public static TypeTracker GetTypeTracker(Type type) {
  94. TypeTracker res;
  95. lock (_typeCache) {
  96. if (!_typeCache.TryGetValue(type, out res)) {
  97. _typeCache[type] = res = new NestedTypeTracker(type);
  98. }
  99. }
  100. return res;
  101. }
  102. /// <summary>
  103. /// TODO: Make me private again
  104. /// </summary>
  105. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] // TODO: fix
  106. public class MethodBaseCache {
  107. private readonly MethodBase[] _members;
  108. private readonly string _name;
  109. public MethodBaseCache(string name, MethodBase[] members) {
  110. // sort by module ID / token so that the Equals / GetHashCode doesn't have
  111. // to line up members if reflection returns them in different orders.
  112. Array.Sort(members, CompareMethods);
  113. _name = name;
  114. _members = members;
  115. }
  116. private static int CompareMethods(MethodBase x, MethodBase y) {
  117. if (x.Module == y.Module) {
  118. return x.MetadataToken - y.MetadataToken;
  119. }
  120. #if SILVERLIGHT
  121. int xHash = x.Module.GetHashCode();
  122. int yHash = y.Module.GetHashCode();
  123. if (xHash != yHash) {
  124. return xHash - yHash;
  125. } else {
  126. long diff = IdDispenser.GetId(x.Module) - IdDispenser.GetId(y.Module);
  127. if (diff > 0) {
  128. return 1;
  129. } else if (diff < 0) {
  130. return -1;
  131. } else {
  132. return 0;
  133. }
  134. }
  135. #else
  136. return x.Module.ModuleVersionId.CompareTo(y.Module.ModuleVersionId);
  137. #endif
  138. }
  139. [Confined]
  140. public override bool Equals(object obj) {
  141. MethodBaseCache other = obj as MethodBaseCache;
  142. if (other == null || _members.Length != other._members.Length || other._name != _name) {
  143. return false;
  144. }
  145. for (int i = 0; i < _members.Length; i++) {
  146. if (_members[i].DeclaringType != other._members[i].DeclaringType ||
  147. _members[i].MetadataToken != other._members[i].MetadataToken ||
  148. _members[i].IsGenericMethod != other._members[i].IsGenericMethod) {
  149. return false;
  150. }
  151. if (_members[i].IsGenericMethod) {
  152. Type[] args = _members[i].GetGenericArguments();
  153. Type[] otherArgs = other._members[i].GetGenericArguments();
  154. if (args.Length != otherArgs.Length) {
  155. return false;
  156. }
  157. for (int j = 0; j < args.Length; j++) {
  158. if (args[j] != otherArgs[j]) {
  159. return false;
  160. }
  161. }
  162. }
  163. }
  164. return true;
  165. }
  166. [Confined]
  167. public override int GetHashCode() {
  168. int res = 6551;
  169. foreach (MemberInfo mi in _members) {
  170. res ^= res << 5 ^ mi.DeclaringType.GetHashCode() ^ mi.MetadataToken;
  171. }
  172. res ^= _name.GetHashCode();
  173. return res;
  174. }
  175. }
  176. }
  177. }