You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
8.7 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. using System;
  2. using System.Reflection;
  3. using UnityEngine;
  4. namespace IPA.Utilities
  5. {
  6. /// <summary>
  7. /// A utility class providing reflection helper methods.
  8. /// </summary>
  9. public static class ReflectionUtil
  10. {
  11. /// <summary>
  12. /// Sets a (potentially) private field on the target object.
  13. /// </summary>
  14. /// <param name="obj">the object instance</param>
  15. /// <param name="fieldName">the field to set</param>
  16. /// <param name="value">the value to set it to</param>
  17. public static void SetPrivateField(this object obj, string fieldName, object value)
  18. {
  19. var prop = obj.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
  20. prop?.SetValue(obj, value);
  21. }
  22. /// <summary>
  23. /// Gets the value of a (potentially) private field.
  24. /// </summary>
  25. /// <typeparam name="T">the type of te field (result casted)</typeparam>
  26. /// <param name="obj">the object instance to pull from</param>
  27. /// <param name="fieldName">the name of the field to read</param>
  28. /// <returns>the value of the field</returns>
  29. public static T GetPrivateField<T>(this object obj, string fieldName)
  30. {
  31. var prop = obj.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
  32. var value = prop?.GetValue(obj);
  33. return (T) value;
  34. }
  35. /// <summary>
  36. /// Sets a (potentially) private property on the target object.
  37. /// </summary>
  38. /// <param name="obj">the target object instance</param>
  39. /// <param name="propertyName">the name of the property</param>
  40. /// <param name="value">the value to set it to</param>
  41. public static void SetPrivateProperty(this object obj, string propertyName, object value)
  42. {
  43. var prop = obj.GetType()
  44. .GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
  45. prop?.SetValue(obj, value, null);
  46. }
  47. /// <summary>
  48. /// Invokes a (potentially) private method.
  49. /// </summary>
  50. /// <param name="obj">the object to call from</param>
  51. /// <param name="methodName">the method name</param>
  52. /// <param name="methodParams">the method parameters</param>
  53. /// <returns>the return value</returns>
  54. public static object InvokePrivateMethod(this object obj, string methodName, params object[] methodParams)
  55. {
  56. MethodInfo dynMethod = obj.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
  57. return dynMethod?.Invoke(obj, methodParams);
  58. }
  59. /// <summary>
  60. /// Invokes a (potentially) private method.
  61. /// </summary>
  62. /// <typeparam name="T">the return type</typeparam>
  63. /// <param name="obj">the object to call from</param>
  64. /// <param name="methodName">the method name to call</param>
  65. /// <param name="methodParams">the method's parameters</param>
  66. /// <returns>the return value</returns>
  67. public static T InvokePrivateMethod<T>(this object obj, string methodName, params object[] methodParams)
  68. {
  69. return (T)InvokePrivateMethod(obj, methodName, methodParams);
  70. }
  71. /// <summary>
  72. /// Copies a component <paramref name="original"/> to a component of <paramref name="overridingType"/> on the destination <see cref="GameObject"/>.
  73. /// </summary>
  74. /// <param name="original">the original component</param>
  75. /// <param name="overridingType">the new component's type</param>
  76. /// <param name="destination">the destination GameObject</param>
  77. /// <param name="originalTypeOverride">overrides the source component type (for example, to a superclass)</param>
  78. /// <returns>the copied component</returns>
  79. public static Component CopyComponent(this Component original, Type overridingType, GameObject destination, Type originalTypeOverride = null)
  80. {
  81. var copy = destination.AddComponent(overridingType);
  82. var originalType = originalTypeOverride ?? original.GetType();
  83. Type type = originalType;
  84. while (type != typeof(MonoBehaviour))
  85. {
  86. CopyForType(type, original, copy);
  87. type = type?.BaseType;
  88. }
  89. return copy;
  90. }
  91. /// <summary>
  92. /// A generic version of <see cref="CopyComponent(Component, Type, GameObject, Type)"/>.
  93. /// </summary>
  94. /// <seealso cref="CopyComponent(Component, Type, GameObject, Type)"/>
  95. /// <typeparam name="T">the overriding type</typeparam>
  96. /// <param name="original">the original component</param>
  97. /// <param name="destination">the destination game object</param>
  98. /// <param name="originalTypeOverride">overrides the source component type (for example, to a superclass)</param>
  99. /// <returns>the copied component</returns>
  100. public static T CopyComponent<T>(this Component original, GameObject destination, Type originalTypeOverride = null)
  101. where T : Component
  102. {
  103. var copy = destination.AddComponent<T>();
  104. var originalType = originalTypeOverride ?? original.GetType();
  105. Type type = originalType;
  106. while (type != typeof(MonoBehaviour))
  107. {
  108. CopyForType(type, original, copy);
  109. type = type?.BaseType;
  110. }
  111. return copy;
  112. }
  113. private static void CopyForType(Type type, Component source, Component destination)
  114. {
  115. FieldInfo[] myObjectFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField);
  116. foreach (FieldInfo fi in myObjectFields)
  117. {
  118. fi.SetValue(destination, fi.GetValue(source));
  119. }
  120. }
  121. /// <summary>
  122. /// Calls an instance method on a type specified by <paramref name="functionClass"/> and <paramref name="dependency"/>.
  123. /// </summary>
  124. /// <seealso cref="CallNonStaticMethod(Type, string, Type[], object[])"/>
  125. /// <param name="functionClass">the type name</param>
  126. /// <param name="dependency">the assembly the type is in</param>
  127. /// <param name="function">the name of the method to call</param>
  128. /// <param name="methodSig">the type signature of the method</param>
  129. /// <param name="parameters">the method parameters</param>
  130. /// <returns>the result of the call</returns>
  131. public static object CallNonStaticMethod(string functionClass, string dependency, string function, Type[] methodSig, params object[] parameters)
  132. {
  133. return CallNonStaticMethod(Type.GetType(string.Format("{0},{1}", functionClass, dependency)), function, methodSig, parameters);
  134. }
  135. /// <summary>
  136. /// Calls an instance method on a new object.
  137. /// </summary>
  138. /// <param name="type">the object type</param>
  139. /// <param name="function">the name of the method to call</param>
  140. /// <param name="methodSig">the type signature</param>
  141. /// <param name="parameters">the parameters</param>
  142. /// <returns>the result of the call</returns>
  143. public static object CallNonStaticMethod(this Type type, /*string functionClass, string dependency,*/ string function, Type[] methodSig, params object[] parameters)
  144. {
  145. //Type FunctionClass = Type.GetType(string.Format("{0},{1}", functionClass, dependency));
  146. if (type != null)
  147. {
  148. object instance = Activator.CreateInstance(type);
  149. {
  150. Type instType = instance.GetType();
  151. MethodInfo methodInfo = instType.GetMethod(function, methodSig);
  152. if (methodInfo != null)
  153. {
  154. return methodInfo.Invoke(instance, parameters);
  155. }
  156. throw new Exception("Method not found");
  157. }
  158. }
  159. throw new ArgumentNullException(nameof(type));
  160. }
  161. /// <summary>
  162. /// Calls an instance method on a new object.
  163. /// </summary>
  164. /// <seealso cref="CallNonStaticMethod(Type, string, Type[], object[])"/>
  165. /// <typeparam name="T">the return type</typeparam>
  166. /// <param name="type">the object type</param>
  167. /// <param name="function">the name of the method to call</param>
  168. /// <param name="methodSig">the type signature</param>
  169. /// <param name="parameters">the parameters</param>
  170. /// <returns>the result of the call</returns>
  171. public static T CallNonStaticMethod<T>(this Type type, string function, Type[] methodSig, params object[] parameters)
  172. {
  173. return (T)CallNonStaticMethod(type, function, methodSig, parameters);
  174. }
  175. }
  176. }