using System; using System.Reflection; using UnityEngine; namespace IPA.Utilities { /// /// A utility class providing reflection helper methods. /// public static class ReflectionUtil { /// /// Sets a (potentially) private field on the target object. /// /// the object instance /// the field to set /// the value to set it to /// thrown when is not a member of public static void SetPrivateField(this object obj, string fieldName, object value) { Type targetType = obj.GetType(); obj.SetPrivateField(fieldName, value, targetType); } /// /// Sets a (potentially) private field on the target object. specifies the the field belongs to. /// /// the object instance /// the field to set /// the value to set it to /// the object the field belongs to /// thrown when is not a member of /// thrown when isn't assignable as public static void SetPrivateField(this object obj, string fieldName, object value, Type targetType) { var prop = targetType.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); if (prop == null) throw new InvalidOperationException($"{fieldName} is not a member of {targetType.Name}"); prop.SetValue(obj, value); } /// /// Gets the value of a (potentially) private field. /// /// the type of te field (result casted) /// the object instance to pull from /// the name of the field to read /// the value of the field /// thrown when is not a member of public static T GetPrivateField(this object obj, string fieldName) { Type targetType = obj.GetType(); return obj.GetPrivateField(fieldName, targetType); } /// /// Gets the value of a (potentially) private field. specifies the the field belongs to. /// /// the type of the field (result casted) /// the object instance to pull from /// the name of the field to read /// the object the field belongs to /// the value of the field /// thrown when is not a member of /// thrown when isn't assignable as public static T GetPrivateField(this object obj, string fieldName, Type targetType) { var prop = targetType.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); if (prop == null) throw new InvalidOperationException($"{fieldName} is not a member of {targetType.Name}"); var value = prop.GetValue(obj); return (T)value; } /// /// Sets a (potentially) private property on the target object. /// /// the target object instance /// the name of the property /// the value to set it to /// thrown when is not a member of public static void SetPrivateProperty(this object obj, string propertyName, object value) { Type targetType = obj.GetType(); obj.SetPrivateProperty(propertyName, value, targetType); } /// /// Sets a (potentially) private property on the target object. /// /// the target object instance /// the name of the property /// the value to set it to /// the object the property belongs to /// thrown when is not a member of /// thrown when isn't assignable as public static void SetPrivateProperty(this object obj, string propertyName, object value, Type targetType) { var prop = targetType .GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); if (prop == null) throw new InvalidOperationException($"{propertyName} is not a member of {targetType.Name}"); prop.SetValue(obj, value, null); } /// /// Invokes a (potentially) private method. /// /// the object to call from /// the method name /// the method parameters /// the return value /// thrown when is not a member of public static object InvokePrivateMethod(this object obj, string methodName, params object[] methodParams) { Type targetType = obj.GetType(); MethodInfo dynMethod = targetType.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); if (dynMethod == null) throw new InvalidOperationException($"{methodName} is not a member of {targetType.Name}"); return dynMethod.Invoke(obj, methodParams); } /// /// Invokes a (potentially) private method. /// /// the return type /// the object to call from /// the method name to call /// the method's parameters /// the return value public static T InvokePrivateMethod(this object obj, string methodName, params object[] methodParams) { return (T)InvokePrivateMethod(obj, methodName, methodParams); } /// /// Copies a component to a component of on the destination . /// /// the original component /// the new component's type /// the destination GameObject /// overrides the source component type (for example, to a superclass) /// the copied component public static Component CopyComponent(this Component original, Type overridingType, GameObject destination, Type originalTypeOverride = null) { var copy = destination.AddComponent(overridingType); var originalType = originalTypeOverride ?? original.GetType(); Type type = originalType; while (type != typeof(MonoBehaviour)) { CopyForType(type, original, copy); type = type?.BaseType; } return copy; } /// /// A generic version of . /// /// /// the overriding type /// the original component /// the destination game object /// overrides the source component type (for example, to a superclass) /// the copied component public static T CopyComponent(this Component original, GameObject destination, Type originalTypeOverride = null) where T : Component { var copy = destination.AddComponent(); var originalType = originalTypeOverride ?? original.GetType(); Type type = originalType; while (type != typeof(MonoBehaviour)) { CopyForType(type, original, copy); type = type?.BaseType; } return copy; } private static void CopyForType(Type type, Component source, Component destination) { FieldInfo[] myObjectFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField); foreach (FieldInfo fi in myObjectFields) { fi.SetValue(destination, fi.GetValue(source)); } } /// /// Calls an instance method on a type specified by and . /// /// /// the type name /// the assembly the type is in /// the name of the method to call /// the type signature of the method /// the method parameters /// the result of the call public static object CallNonStaticMethod(string functionClass, string dependency, string function, Type[] methodSig, params object[] parameters) { return CallNonStaticMethod(Type.GetType(string.Format("{0},{1}", functionClass, dependency)), function, methodSig, parameters); } /// /// Calls an instance method on a new object. /// /// the object type /// the name of the method to call /// the type signature /// the parameters /// the result of the call public static object CallNonStaticMethod(this Type type, /*string functionClass, string dependency,*/ string function, Type[] methodSig, params object[] parameters) { //Type FunctionClass = Type.GetType(string.Format("{0},{1}", functionClass, dependency)); if (type != null) { object instance = Activator.CreateInstance(type); { Type instType = instance.GetType(); MethodInfo methodInfo = instType.GetMethod(function, methodSig); if (methodInfo != null) { return methodInfo.Invoke(instance, parameters); } throw new Exception("Method not found"); } } throw new ArgumentNullException(nameof(type)); } /// /// Calls an instance method on a new object. /// /// /// the return type /// the object type /// the name of the method to call /// the type signature /// the parameters /// the result of the call public static T CallNonStaticMethod(this Type type, string function, Type[] methodSig, params object[] parameters) { return (T)CallNonStaticMethod(type, function, methodSig, parameters); } } }