using System; using System.Linq; using System.Reflection; using UnityEditor; namespace FullscreenEditor { /// Class containing method extensions for getting private and internal members. public static class ReflectionUtility { private static Assembly[] cachedAssemblies; public const BindingFlags FULL_BINDING = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; /// Find a type by its name. public static Type FindClass(string name) { // return typeof(Editor).Assembly.GetType(name, false, true); var result = FindTypeInAssembly(name, typeof(Editor).Assembly); if (result != null) return result; if (cachedAssemblies == null) cachedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); for (var i = 0; i < cachedAssemblies.Length; i++) { result = FindTypeInAssembly(name, cachedAssemblies[i]); if (result != null) return result; } return result; } private static Type FindTypeInAssembly(string name, Assembly assembly) { return assembly == null ? null : assembly.GetType(name, false, true); } /// Find a field of a type by its name. public static FieldInfo FindField(this Type type, string fieldName, bool throwNotFound = true) { if (type == null) throw new ArgumentNullException("type"); var field = type.GetField(fieldName, FULL_BINDING); if (field == null && throwNotFound) throw new MissingFieldException(type.FullName, fieldName); return field; } /// Find a property of a type by its name. public static PropertyInfo FindProperty(this Type type, string propertyName, bool throwNotFound = true) { if (type == null) throw new ArgumentNullException("type"); var prop = type.GetProperty(propertyName, FULL_BINDING); if (prop == null && throwNotFound) throw new MissingMemberException(type.FullName, propertyName); return prop; } /// Find a method of a type by its name. public static MethodInfo FindMethod(this Type type, string methodName, Type[] args = null, bool throwNotFound = true) { if (type == null) throw new ArgumentNullException("type"); MethodInfo method; if (args == null) { method = type.GetMethod(methodName, FULL_BINDING); // method = type.GetMethods(FULL_BINDING) // .Where(m => m.Name == methodName) // .FirstOrDefault(); } else { method = type.GetMethod(methodName, FULL_BINDING, null, args, null); // There are very specific cases where the above method may not bind properly // e.g. when the method declares an enum and the arg type is an int, so we ignore the args // and hope that there are no ambiguity of methods if (method == null) { method = FindMethod(type, methodName, null, throwNotFound); if (method != null && method.GetParameters().Length != args.Length) method = null; } } if (method == null && throwNotFound) throw new MissingMethodException(type.FullName, methodName); return method; } /// Get the value of the static field. public static T GetFieldValue(this Type type, string fieldName) { return (T)type.FindField(fieldName).GetValue(null); } /// Get the value of the instance field. public static T GetFieldValue(this object obj, string fieldName) { return (T)obj.GetType().FindField(fieldName).GetValue(obj); } /// Set the value of the static field. public static void SetFieldValue(this Type type, string fieldName, object value) { type.FindField(fieldName).SetValue(null, value); } /// Set the value of the instance field. public static void SetFieldValue(this object obj, string fieldName, object value) { obj.GetType().FindField(fieldName).SetValue(obj, value); } /// Get the value of the static property. public static T GetPropertyValue(this Type type, string propertyName) { return (T)type.FindProperty(propertyName).GetValue(null, null); } /// Get the value of the instance property. public static T GetPropertyValue(this object obj, string propertyName) { return (T)obj.GetType().FindProperty(propertyName).GetValue(obj, null); } /// Set the value of the static property. public static void SetPropertyValue(this Type type, string propertyName, object value) { type.FindProperty(propertyName).SetValue(null, value, null); } /// Set the value of the instance property. public static void SetPropertyValue(this object obj, string propertyName, object value) { obj.GetType().FindProperty(propertyName).SetValue(obj, value, null); } /// Invoke a static method on the type and return the result. public static T InvokeMethod(this Type type, string methodName, params object[] args) { return (T)type.FindMethod(methodName, args.Select(a => a.GetType()).ToArray()).Invoke(null, args); } /// Invoke a method on the object instance and return the result. public static T InvokeMethod(this object obj, string methodName, params object[] args) { return (T)obj.GetType().FindMethod(methodName, args.Select(a => a.GetType()).ToArray()).Invoke(obj, args); } /// Invoke a static method on the type. public static void InvokeMethod(this Type type, string methodName, params object[] args) { type.FindMethod(methodName, args.Select(a => a.GetType()).ToArray()).Invoke(null, args); } /// Invoke a method on the object instance. public static void InvokeMethod(this object obj, string methodName, params object[] args) { obj.GetType().FindMethod(methodName, args.Select(a => a.GetType()).ToArray()).Invoke(obj, args); } /// Returns wheter the given type is the same as another one. /// Type that will be checked. /// Type to check against. /// Returns true if the checked type is inherited from the type argument. public static bool IsOfType(this Type toCheck, Type type, bool orInherited = true) { return type == toCheck || (orInherited && type.IsAssignableFrom(toCheck)); } /// Returns wheter the given instance is of a given type. /// The instance to check. /// Type to check against. /// Returns true if the instance is inherited from the type argument. public static bool IsOfType(this T obj, Type type, bool orInherited = true) { return obj.GetType().IsOfType(type, orInherited); } /// Throws an exception if the instance is not of the given type. /// The instance to check. /// Type to check against. /// Do not throw if the instance is inherited from the type argument. public static void EnsureOfType(this T obj, Type type, bool orInherited = true) { if (!obj.IsOfType(type, orInherited)) throw new InvalidCastException( string.Format("Object {0} must be of type {1}{2}", obj.GetType().FullName, type.FullName, orInherited? " or inherited from it": "" ) ); } /// Returns whether the type defines the static field. public static bool HasField(this Type type, string fieldName) { return type.FindField(fieldName, false) != null; } /// Returns whether the type defines the static property. public static bool HasProperty(this Type type, string propertyName) { return type.FindProperty(propertyName, false) != null; } /// Returns whether the type defines the static method. public static bool HasMethod(this Type type, string methodName, Type[] args = null) { return type.FindMethod(methodName, args, false) != null; } /// Returns whether the object type defines the instance field. public static bool HasField(this object obj, string fieldName) { return obj.GetType().HasField(fieldName); } /// Returns whether the object type defines the instance property. public static bool HasProperty(this object obj, string propertyName) { return obj.GetType().HasProperty(propertyName); } /// Returns whether the object type defines the instance method. public static bool HasMethod(this object obj, string methodName, Type[] args = null) { return obj.GetType().HasMethod(methodName, args); } } }