#if !UNITY_EDITOR && UNITY_METRO && !ENABLE_IL2CPP #define USE_TYPEINFO #if !UNITY_WINRT_10_0 #define USE_TYPEINFO_EXTENSIONS #endif #endif using System; using System.Collections.Generic; using System.Linq; using System.Reflection; #if USE_TYPEINFO namespace System { public static class AssemblyExtensions { #if USE_TYPEINFO_EXTENSIONS public static Type[] GetTypes(this Assembly assembly) { TypeInfo[] infos = assembly.DefinedTypes.ToArray(); Type[] types = new Type[infos.Length]; for (int i = 0; i < infos.Length; ++i) { types[i] = infos[i].AsType(); } return types; } #endif public static Type GetType(this Assembly assembly, string name, bool throwOnError) { var types = assembly.GetTypes(); for (int i = 0; i < types.Length; ++i) { if (types[i].Name == name) { return types[i]; } } if (throwOnError) throw new Exception("Type " + name + " was not found"); return null; } } } #endif namespace FullSerializer.Internal { /// /// This wraps reflection types so that it is portable across different Unity runtimes. /// public static class fsPortableReflection { public static Type[] EmptyTypes = { }; #region Attribute Queries #if USE_TYPEINFO public static TAttribute GetAttribute(Type type) where TAttribute : Attribute { return GetAttribute(type.GetTypeInfo()); } public static Attribute GetAttribute(Type type, Type attributeType) { return GetAttribute(type.GetTypeInfo(), attributeType, /*shouldCache:*/false); } public static bool HasAttribute(Type type, Type attributeType) { return GetAttribute(type, attributeType) != null; } #endif /// /// Returns true if the given attribute is defined on the given element. /// public static bool HasAttribute(MemberInfo element) { return HasAttribute(element, typeof(TAttribute)); } /// /// Returns true if the given attribute is defined on the given element. /// public static bool HasAttribute(MemberInfo element, bool shouldCache) { return HasAttribute(element, typeof(TAttribute), shouldCache); } /// /// Returns true if the given attribute is defined on the given element. /// public static bool HasAttribute(MemberInfo element, Type attributeType) { return HasAttribute(element, attributeType, true); } /// /// Returns true if the given attribute is defined on the given element. /// public static bool HasAttribute(MemberInfo element, Type attributeType, bool shouldCache) { return element.IsDefined(attributeType, true); } /// /// Fetches the given attribute from the given MemberInfo. This method applies caching /// and is allocation free (after caching has been performed). /// /// The MemberInfo the get the attribute from. /// The type of attribute to fetch. /// The attribute or null. public static Attribute GetAttribute(MemberInfo element, Type attributeType, bool shouldCache) { var query = new AttributeQuery { MemberInfo = element, AttributeType = attributeType }; Attribute attribute; if (_cachedAttributeQueries.TryGetValue(query, out attribute) == false) { var attributes = element.GetCustomAttributes(attributeType, /*inherit:*/ true); if (attributes.Length > 0) attribute = (Attribute)attributes[0]; if (shouldCache) _cachedAttributeQueries[query] = attribute; } return attribute; } /// /// Fetches the given attribute from the given MemberInfo. /// /// The type of attribute to fetch. /// The MemberInfo to get the attribute from. /// Should this computation be cached? If this is the only time it will ever be done, don't bother caching. /// The attribute or null. public static TAttribute GetAttribute(MemberInfo element, bool shouldCache) where TAttribute : Attribute { return (TAttribute)GetAttribute(element, typeof(TAttribute), shouldCache); } public static TAttribute GetAttribute(MemberInfo element) where TAttribute : Attribute { return GetAttribute(element, /*shouldCache:*/true); } private struct AttributeQuery { public MemberInfo MemberInfo; public Type AttributeType; } private static IDictionary _cachedAttributeQueries = new Dictionary(new AttributeQueryComparator()); private class AttributeQueryComparator : IEqualityComparer { public bool Equals(AttributeQuery x, AttributeQuery y) { return x.MemberInfo == y.MemberInfo && x.AttributeType == y.AttributeType; } public int GetHashCode(AttributeQuery obj) { return obj.MemberInfo.GetHashCode() + (17 * obj.AttributeType.GetHashCode()); } } #endregion #if !USE_TYPEINFO private static BindingFlags DeclaredFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; #endif public static PropertyInfo GetDeclaredProperty(this Type type, string propertyName) { var props = GetDeclaredProperties(type); for (int i = 0; i < props.Length; ++i) { if (props[i].Name == propertyName) { return props[i]; } } return null; } public static MethodInfo GetDeclaredMethod(this Type type, string methodName) { var methods = GetDeclaredMethods(type); for (int i = 0; i < methods.Length; ++i) { if (methods[i].Name == methodName) { return methods[i]; } } return null; } public static ConstructorInfo GetDeclaredConstructor(this Type type, Type[] parameters) { var ctors = GetDeclaredConstructors(type); for (int i = 0; i < ctors.Length; ++i) { var ctor = ctors[i]; var ctorParams = ctor.GetParameters(); if (parameters.Length != ctorParams.Length) continue; for (int j = 0; j < ctorParams.Length; ++j) { // require an exact match if (ctorParams[j].ParameterType != parameters[j]) continue; } return ctor; } return null; } public static ConstructorInfo[] GetDeclaredConstructors(this Type type) { #if USE_TYPEINFO return type.GetTypeInfo().DeclaredConstructors.ToArray(); #else return type.GetConstructors(DeclaredFlags); #endif } public static MemberInfo[] GetFlattenedMember(this Type type, string memberName) { var result = new List(); while (type != null) { var members = GetDeclaredMembers(type); for (int i = 0; i < members.Length; ++i) { if (members[i].Name == memberName) { result.Add(members[i]); } } type = type.Resolve().BaseType; } return result.ToArray(); } public static MethodInfo GetFlattenedMethod(this Type type, string methodName) { while (type != null) { var methods = GetDeclaredMethods(type); for (int i = 0; i < methods.Length; ++i) { if (methods[i].Name == methodName) { return methods[i]; } } type = type.Resolve().BaseType; } return null; } public static IEnumerable GetFlattenedMethods(this Type type, string methodName) { while (type != null) { var methods = GetDeclaredMethods(type); for (int i = 0; i < methods.Length; ++i) { if (methods[i].Name == methodName) { yield return methods[i]; } } type = type.Resolve().BaseType; } } public static PropertyInfo GetFlattenedProperty(this Type type, string propertyName) { while (type != null) { var properties = GetDeclaredProperties(type); for (int i = 0; i < properties.Length; ++i) { if (properties[i].Name == propertyName) { return properties[i]; } } type = type.Resolve().BaseType; } return null; } public static MemberInfo GetDeclaredMember(this Type type, string memberName) { var members = GetDeclaredMembers(type); for (int i = 0; i < members.Length; ++i) { if (members[i].Name == memberName) { return members[i]; } } return null; } public static MethodInfo[] GetDeclaredMethods(this Type type) { #if USE_TYPEINFO return type.GetTypeInfo().DeclaredMethods.ToArray(); #else return type.GetMethods(DeclaredFlags); #endif } public static PropertyInfo[] GetDeclaredProperties(this Type type) { #if USE_TYPEINFO return type.GetTypeInfo().DeclaredProperties.ToArray(); #else return type.GetProperties(DeclaredFlags); #endif } public static FieldInfo[] GetDeclaredFields(this Type type) { #if USE_TYPEINFO return type.GetTypeInfo().DeclaredFields.ToArray(); #else return type.GetFields(DeclaredFlags); #endif } public static MemberInfo[] GetDeclaredMembers(this Type type) { #if USE_TYPEINFO return type.GetTypeInfo().DeclaredMembers.ToArray(); #else return type.GetMembers(DeclaredFlags); #endif } public static MemberInfo AsMemberInfo(Type type) { #if USE_TYPEINFO return type.GetTypeInfo(); #else return type; #endif } public static bool IsType(MemberInfo member) { #if USE_TYPEINFO return member is TypeInfo; #else return member is Type; #endif } public static Type AsType(MemberInfo member) { #if USE_TYPEINFO return ((TypeInfo)member).AsType(); #else return (Type)member; #endif } #if USE_TYPEINFO public static TypeInfo Resolve(this Type type) { return type.GetTypeInfo(); } #else public static Type Resolve(this Type type) { return type; } #endif #region Extensions #if USE_TYPEINFO_EXTENSIONS public static bool IsAssignableFrom(this Type parent, Type child) { return parent.GetTypeInfo().IsAssignableFrom(child.GetTypeInfo()); } public static Type GetElementType(this Type type) { return type.GetTypeInfo().GetElementType(); } public static MethodInfo GetSetMethod(this PropertyInfo member, bool nonPublic = false) { // only public requested but the set method is not public if (nonPublic == false && member.SetMethod != null && member.SetMethod.IsPublic == false) return null; return member.SetMethod; } public static MethodInfo GetGetMethod(this PropertyInfo member, bool nonPublic = false) { // only public requested but the set method is not public if (nonPublic == false && member.GetMethod != null && member.GetMethod.IsPublic == false) return null; return member.GetMethod; } public static MethodInfo GetBaseDefinition(this MethodInfo method) { return method.GetRuntimeBaseDefinition(); } public static Type[] GetInterfaces(this Type type) { return type.GetTypeInfo().ImplementedInterfaces.ToArray(); } public static Type[] GetGenericArguments(this Type type) { return type.GetTypeInfo().GenericTypeArguments.ToArray(); } #endif #endregion } }