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);
}
}
}