ReflectionCache.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Text;
  6. namespace XUnity.RuntimeHooker.Core.Utilities
  7. {
  8. public static class ReflectionCache
  9. {
  10. private static Dictionary<MemberLookupKey, CachedMethod> Methods = new Dictionary<MemberLookupKey, CachedMethod>();
  11. private static Dictionary<MemberLookupKey, CachedProperty> Properties = new Dictionary<MemberLookupKey, CachedProperty>();
  12. public static CachedMethod CachedMethod( this Type type, string name )
  13. {
  14. var key = new MemberLookupKey( type, name );
  15. if( !Methods.TryGetValue( key, out var cachedMember ) )
  16. {
  17. var currentType = type;
  18. MethodInfo method = null;
  19. while( method == null && currentType != null )
  20. {
  21. method = currentType.GetMethod( name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic );
  22. currentType = currentType.BaseType;
  23. }
  24. if( method != null )
  25. {
  26. cachedMember = new CachedMethod( method );
  27. }
  28. // also cache nulls!
  29. Methods[ key ] = cachedMember;
  30. }
  31. return cachedMember;
  32. }
  33. public static CachedProperty CachedProperty( this Type type, string name )
  34. {
  35. var key = new MemberLookupKey( type, name );
  36. if( !Properties.TryGetValue( key, out var cachedMember ) )
  37. {
  38. var currentType = type;
  39. PropertyInfo property = null;
  40. while( property == null && currentType != null )
  41. {
  42. property = currentType.GetProperty( name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic );
  43. currentType = currentType.BaseType;
  44. }
  45. if( property != null )
  46. {
  47. cachedMember = new CachedProperty( property );
  48. }
  49. // also cache nulls!
  50. Properties[ key ] = cachedMember;
  51. }
  52. return cachedMember;
  53. }
  54. public struct MemberLookupKey
  55. {
  56. public MemberLookupKey( Type type, string memberName )
  57. {
  58. Type = type;
  59. MemberName = memberName;
  60. }
  61. public Type Type { get; set; }
  62. public string MemberName { get; set; }
  63. // override object.Equals
  64. public override bool Equals( object obj )
  65. {
  66. if( obj is MemberLookupKey key )
  67. {
  68. return Type == key.Type && MemberName == key.MemberName;
  69. }
  70. return false;
  71. }
  72. // override object.GetHashCode
  73. public override int GetHashCode()
  74. {
  75. return Type.GetHashCode() + MemberName.GetHashCode();
  76. }
  77. }
  78. }
  79. public class CachedMethod
  80. {
  81. private static readonly object[] Args0 = new object[ 0 ];
  82. private static readonly object[] Args1 = new object[ 1 ];
  83. private static readonly object[] Args2 = new object[ 2 ];
  84. private Func<object, object[], object> _invoke;
  85. public CachedMethod( MethodInfo method )
  86. {
  87. _invoke = ExpressionHelper.CreateFastInvoke( method );
  88. }
  89. public object Invoke( object instance, object[] arguments )
  90. {
  91. return _invoke( instance, arguments );
  92. }
  93. public object Invoke( object instance )
  94. {
  95. return _invoke( instance, Args0 );
  96. }
  97. public object Invoke( object instance, object arg1 )
  98. {
  99. try
  100. {
  101. Args1[ 0 ] = arg1;
  102. return _invoke( instance, Args1 );
  103. }
  104. finally
  105. {
  106. Args1[ 0 ] = null;
  107. }
  108. }
  109. public object Invoke( object instance, object arg1, object arg2 )
  110. {
  111. try
  112. {
  113. Args2[ 0 ] = arg1;
  114. Args2[ 1 ] = arg2;
  115. return _invoke( instance, Args2 );
  116. }
  117. finally
  118. {
  119. Args2[ 0 ] = null;
  120. Args2[ 1 ] = null;
  121. }
  122. }
  123. }
  124. public class CachedProperty
  125. {
  126. private static readonly object[] Args0 = new object[ 0 ];
  127. private static readonly object[] Args1 = new object[ 1 ];
  128. private Func<object, object[], object> _set;
  129. private Func<object, object[], object> _get;
  130. public CachedProperty( PropertyInfo propertyInfo )
  131. {
  132. if( propertyInfo.CanRead )
  133. {
  134. _get = ExpressionHelper.CreateFastInvoke( propertyInfo.GetGetMethod() );
  135. }
  136. if( propertyInfo.CanWrite )
  137. {
  138. _set = ExpressionHelper.CreateFastInvoke( propertyInfo.GetSetMethod() );
  139. }
  140. }
  141. public object Set( object instance, object[] arguments )
  142. {
  143. return _set( instance, arguments );
  144. }
  145. public object Set( object instance, object arg1 )
  146. {
  147. try
  148. {
  149. Args1[ 0 ] = arg1;
  150. return _set( instance, Args1 );
  151. }
  152. finally
  153. {
  154. Args1[ 0 ] = null;
  155. }
  156. }
  157. public object Get( object instance, object[] arguments )
  158. {
  159. return _get( instance, arguments );
  160. }
  161. public object Get( object instance )
  162. {
  163. return _get( instance, Args0 );
  164. }
  165. }
  166. }