public static RuntimePropertyHandler GetHandler(RuntimeSerializedProperty property, List <PropertyAttribute> attributes)
        {
            if (property == null)
            {
                return(s_SharedNullHandler);
            }

            // Don't use custom drawers in debug mode
            if (property.RuntimeSerializedObject.SerializedObject.InspectorMode() != InspectorMode.Normal)
            {
                return(s_SharedNullHandler);
            }

            // If the drawer is cached, use the cached drawer
            RuntimePropertyHandler handler = PropertyHandlerCache.GetHandler(property, attributes);

            if (handler != null)
            {
                return(handler);
            }

            Type propertyType = null;
            List <PropertyAttribute> attrs = null;
            FieldInfo field = null;

            // Determine if SerializedObject target is a script or a builtin type
            UnityEngine.Object targetObject = property.RuntimeSerializedObject.TargetObject;
            if (targetObject is MonoBehaviour || targetObject is ScriptableObject)
            {
                // For scripts, use reflection to get FieldInfo for the member the property represents
                field = GetFieldInfoFromProperty(property, out propertyType);

                // Use reflection to see if this member has an attribute
                attrs = GetFieldAttributes(field);
            }
            else
            {
                // For builtin types, look if we hardcoded an attribute for this property
                // First initialize the hardcoded properties if not already done
                if (s_BuiltinAttributes == null)
                {
                    PopulateBuiltinAttributes();
                }

                if (attrs == null)
                {
                    attrs = GetBuiltinAttributes(property);
                }
            }

            if (attributes != null)
            {
                if (attrs != null)
                {
                    attributes.AddRange(attrs);
                }
                attrs = attributes.OrderBy(attr => - attr.order).ToList();
            }

            handler = s_NextHandler;

            if (attrs != null)
            {
                for (int i = attrs.Count - 1; i >= 0; i--)
                {
                    handler.HandleAttribute(attrs[i], field, propertyType);
                }
            }

            // Field has no CustomPropertyDrawer attribute with matching drawer so look for default drawer for field type
            if (!handler.HasRuntimePropertyDrawer && propertyType != null)
            {
                handler.HandleDrawnType(propertyType, propertyType, field, null);
            }

            if (handler.Empty)
            {
                PropertyHandlerCache.SetHandler(property, s_SharedNullHandler, attributes);
                handler = s_SharedNullHandler;
            }
            else
            {
                PropertyHandlerCache.SetHandler(property, handler, attributes);
                s_NextHandler = new RuntimePropertyHandler();
            }

            return(handler);
        }
        public void SetHandler(RuntimeSerializedProperty property, RuntimePropertyHandler handler, List <PropertyAttribute> attributes)
        {
            int key = GetPropertyHash(property, attributes);

            PropertyHandlers[key] = handler;
        }