//---------------------------------------------- // NGUI: Next-Gen UI kit // Copyright © 2011-2015 Tasharen Entertainment //---------------------------------------------- #if UNITY_EDITOR || !UNITY_FLASH #define REFLECTION_SUPPORT #endif #if REFLECTION_SUPPORT using System.Reflection; using System.Diagnostics; #endif using UnityEngine; using System; /// /// Reference to a specific field or property that can be set via inspector. /// [System.Serializable] public class PropertyReference { [SerializeField] Component mTarget; [SerializeField] string mName; #if REFLECTION_SUPPORT FieldInfo mField = null; PropertyInfo mProperty = null; #endif /// /// Event delegate's target object. /// public Component target { get { return mTarget; } set { mTarget = value; #if REFLECTION_SUPPORT mProperty = null; mField = null; #endif } } /// /// Event delegate's method name. /// public string name { get { return mName; } set { mName = value; #if REFLECTION_SUPPORT mProperty = null; mField = null; #endif } } /// /// Whether this delegate's values have been set. /// public bool isValid { get { return (mTarget != null && !string.IsNullOrEmpty(mName)); } } /// /// Whether the target script is actually enabled. /// public bool isEnabled { get { if (mTarget == null) return false; MonoBehaviour mb = (mTarget as MonoBehaviour); return (mb == null || mb.enabled); } } public PropertyReference () { } public PropertyReference (Component target, string fieldName) { mTarget = target; mName = fieldName; } /// /// Helper function that returns the property type. /// public Type GetPropertyType () { #if REFLECTION_SUPPORT if (mProperty == null && mField == null && isValid) Cache(); if (mProperty != null) return mProperty.PropertyType; if (mField != null) return mField.FieldType; #endif #if UNITY_EDITOR || !UNITY_FLASH return typeof(void); #else return null; #endif } /// /// Equality operator. /// public override bool Equals (object obj) { if (obj == null) { return !isValid; } if (obj is PropertyReference) { PropertyReference pb = obj as PropertyReference; return (mTarget == pb.mTarget && string.Equals(mName, pb.mName)); } return false; } static int s_Hash = "PropertyBinding".GetHashCode(); /// /// Used in equality operators. /// public override int GetHashCode () { return s_Hash; } /// /// Set the delegate callback using the target and method names. /// public void Set (Component target, string methodName) { mTarget = target; mName = methodName; } /// /// Clear the event delegate. /// public void Clear () { mTarget = null; mName = null; } /// /// Reset the cached references. /// public void Reset () { #if REFLECTION_SUPPORT mField = null; mProperty = null; #endif } /// /// Convert the delegate to its string representation. /// public override string ToString () { return ToString(mTarget, name); } /// /// Convenience function that converts the specified component + property pair into its string representation. /// static public string ToString (Component comp, string property) { if (comp != null) { string typeName = comp.GetType().ToString(); int period = typeName.LastIndexOf('.'); if (period > 0) typeName = typeName.Substring(period + 1); if (!string.IsNullOrEmpty(property)) return typeName + "." + property; else return typeName + ".[property]"; } return null; } #if REFLECTION_SUPPORT /// /// Retrieve the property's value. /// [DebuggerHidden] [DebuggerStepThrough] public object Get () { if (mProperty == null && mField == null && isValid) Cache(); if (mProperty != null) { if (mProperty.CanRead) return mProperty.GetValue(mTarget, null); } else if (mField != null) { return mField.GetValue(mTarget); } return null; } /// /// Assign the bound property's value. /// [DebuggerHidden] [DebuggerStepThrough] public bool Set (object value) { if (mProperty == null && mField == null && isValid) Cache(); if (mProperty == null && mField == null) return false; if (value == null) { try { if (mProperty != null) { if (mProperty.CanWrite) { mProperty.SetValue(mTarget, null, null); return true; } } else { mField.SetValue(mTarget, null); return true; } } catch (Exception) { return false; } } // Can we set the value? if (!Convert(ref value)) { if (Application.isPlaying) UnityEngine.Debug.LogError("Unable to convert " + value.GetType() + " to " + GetPropertyType()); } else if (mField != null) { mField.SetValue(mTarget, value); return true; } else if (mProperty.CanWrite) { mProperty.SetValue(mTarget, value, null); return true; } return false; } /// /// Cache the field or property. /// [DebuggerHidden] [DebuggerStepThrough] bool Cache () { if (mTarget != null && !string.IsNullOrEmpty(mName)) { Type type = mTarget.GetType(); #if NETFX_CORE mField = type.GetRuntimeField(mName); mProperty = type.GetRuntimeProperty(mName); #else mField = type.GetField(mName); mProperty = type.GetProperty(mName); #endif } else { mField = null; mProperty = null; } return (mField != null || mProperty != null); } /// /// Whether we can assign the property using the specified value. /// bool Convert (ref object value) { if (mTarget == null) return false; Type to = GetPropertyType(); Type from; if (value == null) { #if NETFX_CORE if (!to.GetTypeInfo().IsClass) return false; #else if (!to.IsClass) return false; #endif from = to; } else from = value.GetType(); return Convert(ref value, from, to); } #else // Everything below = no reflection support public object Get () { Debug.LogError("Reflection is not supported on this platform"); return null; } public bool Set (object value) { Debug.LogError("Reflection is not supported on this platform"); return false; } bool Cache () { return false; } bool Convert (ref object value) { return false; } #endif /// /// Whether we can convert one type to another for assignment purposes. /// static public bool Convert (Type from, Type to) { object temp = null; return Convert(ref temp, from, to); } /// /// Whether we can convert one type to another for assignment purposes. /// static public bool Convert (object value, Type to) { if (value == null) { value = null; return Convert(ref value, to, to); } return Convert(ref value, value.GetType(), to); } /// /// Whether we can convert one type to another for assignment purposes. /// static public bool Convert (ref object value, Type from, Type to) { #if REFLECTION_SUPPORT // If the value can be assigned as-is, we're done #if NETFX_CORE if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo())) return true; #else if (to.IsAssignableFrom(from)) return true; #endif #else if (from == to) return true; #endif // If the target type is a string, just convert the value if (to == typeof(string)) { value = (value != null) ? value.ToString() : "null"; return true; } // If the value is null we should not proceed further if (value == null) return false; if (to == typeof(int)) { if (from == typeof(string)) { int val; if (int.TryParse((string)value, out val)) { value = val; return true; } } else if (from == typeof(float)) { value = Mathf.RoundToInt((float)value); return true; } } else if (to == typeof(float)) { if (from == typeof(string)) { float val; if (float.TryParse((string)value, out val)) { value = val; return true; } } } return false; } }