123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
- #if UNITY_EDITOR
- using System;
- using System.Collections.Generic;
- using System.Reflection;
- using UnityEditor;
- using UnityEngine;
- namespace Animancer.Editor
- {
- /// <summary>[Editor-Only] A cache to optimize repeated attribute access.</summary>
- /// <remarks>
- /// If <typeparamref name="TAttribute"/> implements <see cref="IInitializable{T}"/> for <see cref="MemberInfo"/>,
- /// its <see cref="IInitializable{T}.Initialize(T)"/> method will be called automatically.
- /// </remarks>
- /// https://kybernetik.com.au/animancer/api/Animancer.Editor/AttributeCache_1
- public static class AttributeCache<TAttribute>
- where TAttribute : class
- {
- /************************************************************************************************************************/
- private static readonly Dictionary<MemberInfo, TAttribute>
- MemberToAttribute = new();
- /************************************************************************************************************************/
- /// <summary>
- /// Returns the <typeparamref name="TAttribute"/> attribute on the specified `member` (if there is one).
- /// </summary>
- public static TAttribute GetAttribute(MemberInfo member)
- {
- if (!MemberToAttribute.TryGetValue(member, out var attribute))
- {
- try
- {
- attribute = member.GetAttribute<TAttribute>();
- if (attribute is IInitializable<MemberInfo> initializable)
- initializable.Initialize(member);
- }
- catch (Exception exception)
- {
- Debug.LogException(exception);
- attribute = null;
- }
- MemberToAttribute.Add(member, attribute);
- }
- return attribute;
- }
- /************************************************************************************************************************/
- /// <summary>
- /// Returns the <typeparamref name="TAttribute"/> attribute (if any)
- /// on the specified `type` or its <see cref="Type.BaseType"/> (recursively).
- /// </summary>
- public static TAttribute GetAttribute(Type type)
- {
- if (type == null)
- return null;
- var attribute = GetAttribute((MemberInfo)type);
- if (attribute != null)
- return attribute;
- return MemberToAttribute[type] = GetAttribute(type.BaseType);
- }
- /************************************************************************************************************************/
- /// <summary>
- /// Returns the <typeparamref name="TAttribute"/> attribute on the specified `field` or its
- /// <see cref="FieldInfo.FieldType"/> or <see cref="MemberInfo.DeclaringType"/>.
- /// </summary>
- public static TAttribute FindAttribute(FieldInfo field)
- {
- var attribute = GetAttribute(field);
- if (attribute != null)
- return attribute;
- attribute = GetAttribute(field.FieldType);
- if (attribute != null)
- return MemberToAttribute[field] = attribute;
- attribute = GetAttribute(field.DeclaringType);
- if (attribute != null)
- return MemberToAttribute[field] = attribute;
- return attribute;
- }
- /************************************************************************************************************************/
- /// <summary>[Editor-Only]
- /// Returns the <typeparamref name="TAttribute"/> attribute on the underlying field
- /// of the `property` or its <see cref="FieldInfo.FieldType"/> or
- /// <see cref="MemberInfo.DeclaringType"/> or any of the parent properties
- /// or the type of the <see cref="SerializedObject.targetObject"/>.
- /// </summary>
- public static TAttribute FindAttribute(SerializedProperty property)
- {
- var accessor = property.GetAccessor();
- while (accessor != null)
- {
- var field = accessor.GetField(property);
- var attribute = GetAttribute(field);
- if (attribute != null)
- return attribute;
- var value = accessor.GetValue(property);
- if (value != null)
- {
- attribute = GetAttribute(value.GetType());
- if (attribute != null)
- return attribute;
- }
- accessor = accessor.Parent;
- }
- // If none of the fields of types they are declared in have names, try the actual type of the target.
- {
- var attribute = GetAttribute(property.serializedObject.targetObject.GetType());
- if (attribute != null)
- return attribute;
- }
- return null;
- }
- /************************************************************************************************************************/
- }
- }
- #endif
|