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.
208 lines
6.3 KiB
208 lines
6.3 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Reflection; |
|
using System.Text.RegularExpressions; |
|
using UnityEngine; |
|
|
|
namespace UnityTest |
|
{ |
|
public class MemberResolver |
|
{ |
|
private object m_CallingObjectRef; |
|
private MemberInfo[] m_Callstack; |
|
private readonly GameObject m_GameObject; |
|
private readonly string m_Path; |
|
|
|
public MemberResolver(GameObject gameObject, string path) |
|
{ |
|
path = path.Trim(); |
|
ValidatePath(path); |
|
|
|
m_GameObject = gameObject; |
|
m_Path = path.Trim(); |
|
} |
|
|
|
public object GetValue(bool useCache) |
|
{ |
|
if (useCache && m_CallingObjectRef != null) |
|
{ |
|
object val = m_CallingObjectRef; |
|
for (int i = 0; i < m_Callstack.Length; i++) |
|
val = GetValueFromMember(val, m_Callstack[i]); |
|
return val; |
|
} |
|
|
|
object result = GetBaseObject(); |
|
var fullCallStack = GetCallstack(); |
|
|
|
m_CallingObjectRef = result; |
|
var tempCallstack = new List<MemberInfo>(); |
|
for (int i = 0; i < fullCallStack.Length; i++) |
|
{ |
|
var member = fullCallStack[i]; |
|
result = GetValueFromMember(result, member); |
|
tempCallstack.Add(member); |
|
if (result == null) return null; |
|
var type = result.GetType(); |
|
|
|
//String is not a value type but we don't want to cache it |
|
if (!IsValueType(type) && type != typeof(System.String)) |
|
{ |
|
tempCallstack.Clear(); |
|
m_CallingObjectRef = result; |
|
} |
|
} |
|
m_Callstack = tempCallstack.ToArray(); |
|
return result; |
|
} |
|
|
|
public Type GetMemberType() |
|
{ |
|
var callstack = GetCallstack(); |
|
if (callstack.Length == 0) return GetBaseObject().GetType(); |
|
|
|
var member = callstack[callstack.Length - 1]; |
|
if (member is FieldInfo) |
|
return (member as FieldInfo).FieldType; |
|
if (member is MethodInfo) |
|
return (member as MethodInfo).ReturnType; |
|
return null; |
|
} |
|
|
|
#region Static wrappers |
|
public static bool TryGetMemberType(GameObject gameObject, string path, out Type value) |
|
{ |
|
try |
|
{ |
|
var mr = new MemberResolver(gameObject, path); |
|
value = mr.GetMemberType(); |
|
return true; |
|
} |
|
catch (InvalidPathException) |
|
{ |
|
value = null; |
|
return false; |
|
} |
|
} |
|
|
|
public static bool TryGetValue(GameObject gameObject, string path, out object value) |
|
{ |
|
try |
|
{ |
|
var mr = new MemberResolver(gameObject, path); |
|
value = mr.GetValue(false); |
|
return true; |
|
} |
|
catch (InvalidPathException) |
|
{ |
|
value = null; |
|
return false; |
|
} |
|
} |
|
#endregion |
|
|
|
private object GetValueFromMember(object obj, MemberInfo memberInfo) |
|
{ |
|
if (memberInfo is FieldInfo) |
|
return (memberInfo as FieldInfo).GetValue(obj); |
|
if (memberInfo is MethodInfo) |
|
return (memberInfo as MethodInfo).Invoke(obj, null); |
|
throw new InvalidPathException(memberInfo.Name); |
|
} |
|
|
|
private object GetBaseObject() |
|
{ |
|
if (string.IsNullOrEmpty(m_Path)) return m_GameObject; |
|
var firstElement = m_Path.Split('.')[0]; |
|
var comp = m_GameObject.GetComponent(firstElement); |
|
if (comp != null) |
|
return comp; |
|
return m_GameObject; |
|
} |
|
|
|
private MemberInfo[] GetCallstack() |
|
{ |
|
if (m_Path == "") return new MemberInfo[0]; |
|
var propsQueue = new Queue<string>(m_Path.Split('.')); |
|
|
|
Type type = GetBaseObject().GetType(); |
|
if (type != typeof(GameObject)) |
|
propsQueue.Dequeue(); |
|
|
|
PropertyInfo propertyTemp; |
|
FieldInfo fieldTemp; |
|
var list = new List<MemberInfo>(); |
|
while (propsQueue.Count != 0) |
|
{ |
|
var nameToFind = propsQueue.Dequeue(); |
|
fieldTemp = GetField(type, nameToFind); |
|
if (fieldTemp != null) |
|
{ |
|
type = fieldTemp.FieldType; |
|
list.Add(fieldTemp); |
|
continue; |
|
} |
|
propertyTemp = GetProperty(type, nameToFind); |
|
if (propertyTemp != null) |
|
{ |
|
type = propertyTemp.PropertyType; |
|
var getMethod = GetGetMethod(propertyTemp); |
|
list.Add(getMethod); |
|
continue; |
|
} |
|
throw new InvalidPathException(nameToFind); |
|
} |
|
return list.ToArray(); |
|
} |
|
|
|
private void ValidatePath(string path) |
|
{ |
|
bool invalid = false; |
|
if (path.StartsWith(".") || path.EndsWith(".")) |
|
invalid = true; |
|
if (path.IndexOf("..") >= 0) |
|
invalid = true; |
|
if (Regex.IsMatch(path, @"\s")) |
|
invalid = true; |
|
|
|
if (invalid) |
|
throw new InvalidPathException(path); |
|
} |
|
|
|
private static bool IsValueType(Type type) |
|
{ |
|
#if !UNITY_METRO |
|
return type.IsValueType; |
|
#else |
|
return false; |
|
#endif |
|
} |
|
|
|
private static FieldInfo GetField(Type type, string fieldName) |
|
{ |
|
#if !UNITY_METRO |
|
return type.GetField(fieldName); |
|
#else |
|
return null; |
|
#endif |
|
} |
|
|
|
private static PropertyInfo GetProperty(Type type, string propertyName) |
|
{ |
|
#if !UNITY_METRO |
|
return type.GetProperty(propertyName); |
|
#else |
|
return null; |
|
#endif |
|
} |
|
|
|
private static MethodInfo GetGetMethod(PropertyInfo propertyInfo) |
|
{ |
|
#if !UNITY_METRO |
|
return propertyInfo.GetGetMethod(); |
|
#else |
|
return null; |
|
#endif |
|
} |
|
} |
|
}
|
|
|