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.

188 lines
8.4 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 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 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 SetField(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. /// Sets a field on the target object, as gotten from <typeparamref name="T"/>.
  24. /// </summary>
  25. /// <typeparam name="T">the type to get the field from</typeparam>
  26. /// <param name="obj">the object instance</param>
  27. /// <param name="fieldName">the field to set</param>
  28. /// <param name="value">the value to set it to</param>
  29. public static void SetField<T>(this T obj, string fieldName, object value) where T : class
  30. {
  31. var prop = typeof(T).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
  32. prop?.SetValue(obj, value);
  33. }
  34. /// <summary>
  35. /// Gets the value of a field.
  36. /// </summary>
  37. /// <typeparam name="T">the type of the field (result casted)</typeparam>
  38. /// <param name="obj">the object instance to pull from</param>
  39. /// <param name="fieldName">the name of the field to read</param>
  40. /// <returns>the value of the field</returns>
  41. public static T GetField<T>(this object obj, string fieldName)
  42. {
  43. var prop = obj.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
  44. var value = prop?.GetValue(obj);
  45. return (T) value;
  46. }
  47. /// <summary>
  48. /// Sets a property on the target object.
  49. /// </summary>
  50. /// <param name="obj">the target object instance</param>
  51. /// <param name="propertyName">the name of the property</param>
  52. /// <param name="value">the value to set it to</param>
  53. public static void SetProperty(this object obj, string propertyName, object value)
  54. {
  55. var prop = obj.GetType().GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
  56. prop?.SetValue(obj, value, null);
  57. }
  58. /// <summary>
  59. /// Sets a property on the target object, as gotten from <typeparamref name="T"/>
  60. /// </summary>
  61. /// <typeparam name="T">the type to get the property from</typeparam>
  62. /// <param name="obj">the object instance</param>
  63. /// <param name="propertyName">the property to set</param>
  64. /// <param name="value">the value to set it to</param>
  65. public static void SetProperty<T>(this T obj, string propertyName, object value) where T : class
  66. {
  67. var prop = typeof(T).GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
  68. prop?.SetValue(obj, value, null);
  69. }
  70. /// <summary>
  71. /// Invokes a method on an object.
  72. /// </summary>
  73. /// <param name="obj">the object to call from</param>
  74. /// <param name="methodName">the method name</param>
  75. /// <param name="methodArgs">the method arguments</param>
  76. /// <returns>the return value</returns>
  77. public static object InvokeMethod(this object obj, string methodName, params object[] methodArgs)
  78. {
  79. MethodInfo dynMethod = obj.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
  80. return dynMethod?.Invoke(obj, methodArgs);
  81. }
  82. /// <summary>
  83. /// Invokes a method from <typeparamref name="T"/> on an object.
  84. /// </summary>
  85. /// <typeparam name="T">the type to search for the method on</typeparam>
  86. /// <param name="obj">the object instance</param>
  87. /// <param name="methodName">the method's name</param>
  88. /// <param name="args">the method arguments</param>
  89. /// <returns>the return value</returns>
  90. public static object InvokeMethod<T>(this T obj, string methodName, params object[] args) where T : class
  91. {
  92. var dynMethod = typeof(T).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
  93. return dynMethod?.Invoke(obj, args);
  94. }
  95. /// <summary>
  96. /// Invokes a method.
  97. /// </summary>
  98. /// <typeparam name="T">the return type</typeparam>
  99. /// <param name="obj">the object instance</param>
  100. /// <param name="methodName">the method name to call</param>
  101. /// <param name="methodArgs">the method's arguments</param>
  102. /// <returns>the return value</returns>
  103. public static T InvokeMethod<T>(this object obj, string methodName, params object[] methodArgs)
  104. {
  105. return (T)InvokeMethod(obj, methodName, methodArgs);
  106. }
  107. /// <summary>
  108. /// Invokes a method from <typeparamref name="U"/> on an object.
  109. /// </summary>
  110. /// <typeparam name="T">the return type</typeparam>
  111. /// <typeparam name="U">the type to search for the method on</typeparam>
  112. /// <param name="obj">the object instance</param>
  113. /// <param name="methodName">the method name to call</param>
  114. /// <param name="methodArgs">the method's arguments</param>
  115. /// <returns>the return value</returns>
  116. public static T InvokeMethod<T, U>(this U obj, string methodName, params object[] methodArgs) where U : class
  117. {
  118. return (T)obj.InvokeMethod(methodName, methodArgs);
  119. }
  120. /// <summary>
  121. /// Copies a component <paramref name="original"/> to a component of <paramref name="overridingType"/> on the destination <see cref="GameObject"/>.
  122. /// </summary>
  123. /// <param name="original">the original component</param>
  124. /// <param name="overridingType">the new component's type</param>
  125. /// <param name="destination">the destination GameObject</param>
  126. /// <param name="originalTypeOverride">overrides the source component type (for example, to a superclass)</param>
  127. /// <returns>the copied component</returns>
  128. public static Component CopyComponent(this Component original, Type overridingType, GameObject destination, Type originalTypeOverride = null)
  129. {
  130. var copy = destination.AddComponent(overridingType);
  131. var originalType = originalTypeOverride ?? original.GetType();
  132. Type type = originalType;
  133. while (type != typeof(MonoBehaviour))
  134. {
  135. CopyForType(type, original, copy);
  136. type = type?.BaseType;
  137. }
  138. return copy;
  139. }
  140. /// <summary>
  141. /// A generic version of <see cref="CopyComponent(Component, Type, GameObject, Type)"/>.
  142. /// </summary>
  143. /// <seealso cref="CopyComponent(Component, Type, GameObject, Type)"/>
  144. /// <typeparam name="T">the overriding type</typeparam>
  145. /// <param name="original">the original component</param>
  146. /// <param name="destination">the destination game object</param>
  147. /// <param name="originalTypeOverride">overrides the source component type (for example, to a superclass)</param>
  148. /// <returns>the copied component</returns>
  149. public static T CopyComponent<T>(this Component original, GameObject destination, Type originalTypeOverride = null)
  150. where T : Component
  151. {
  152. var copy = destination.AddComponent<T>();
  153. var originalType = originalTypeOverride ?? original.GetType();
  154. Type type = originalType;
  155. while (type != typeof(MonoBehaviour))
  156. {
  157. CopyForType(type, original, copy);
  158. type = type?.BaseType;
  159. }
  160. return copy;
  161. }
  162. private static void CopyForType(Type type, Component source, Component destination)
  163. {
  164. FieldInfo[] myObjectFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
  165. foreach (FieldInfo fi in myObjectFields)
  166. {
  167. fi.SetValue(destination, fi.GetValue(source));
  168. }
  169. }
  170. }
  171. }