private void SetValue([NotNull] PropOrField setter, [CanBeNull] object obj, [CanBeNull] object value, [NotNull] Type serializedValueType)
        {
            var acceptedType = setter.GetValueType();

            if (ReferenceEquals(value, null))
            {
                if (acceptedType.IsValueType)
                {
                    throw new InvalidCastException("Cannot cast 'null' to a value type.");
                }
            }

            if (acceptedType.IsEnum)
            {
                if (ReferenceEquals(value, null))
                {
                    throw new ApplicationException("Not possible.");
                }

                if (serializedValueType == typeof(byte) || serializedValueType == typeof(sbyte) ||
                    serializedValueType == typeof(ushort) || serializedValueType == typeof(short) ||
                    serializedValueType == typeof(uint) || serializedValueType == typeof(int) ||
                    serializedValueType == typeof(ulong) || serializedValueType == typeof(long))
                {
                    var enumValue = Enum.ToObject(acceptedType, value);

                    setter.SetValueDirect(obj, enumValue);

                    return;
                }
            }

            var converterType  = setter.Attribute?.ConverterType;
            var convertedValue = TryConvertValueType(serializedValueType, acceptedType, value, converterType);

            setter.SetValueDirect(obj, convertedValue);
        }
        private PropOrField FindSetterByName([NotNull] Type objectType, [NotNull, ItemNotNull] PropertyInfo[] properties, [NotNull, ItemNotNull] FieldInfo[] fields, [NotNull] string name, [CanBeNull] INamingConvention naming)
        {
            PropOrField result;

            foreach (var prop in properties)
            {
                ScriptableObjectPropertyAttribute sopa;

                if (_propertyAttributeCache.ContainsKey(prop))
                {
                    sopa = _propertyAttributeCache[prop];
                }
                else
                {
                    sopa = prop.GetCustomAttribute <ScriptableObjectPropertyAttribute>();
                    _propertyAttributeCache[prop] = sopa;
                }

                var propName = !string.IsNullOrEmpty(sopa?.Name) ? sopa.Name : (naming != null ? naming.GetCorrected(prop.Name) : prop.Name);

                if (propName == name)
                {
                    var key = (objectType, propName, mbp : sopa);

                    if (_createdSetters.ContainsKey(key))
                    {
                        result = _createdSetters[key];
                    }
                    else
                    {
                        result = new PropOrField(prop, sopa);
                        _createdSetters[key] = result;
                    }

                    return(result);
                }
            }

            foreach (var field in fields)
            {
                ScriptableObjectPropertyAttribute sopa;

                if (_fieldAttributeCache.ContainsKey(field))
                {
                    sopa = _fieldAttributeCache[field];
                }
                else
                {
                    sopa = field.GetCustomAttribute <ScriptableObjectPropertyAttribute>();
                    _fieldAttributeCache[field] = sopa;
                }

                var fieldName = !string.IsNullOrEmpty(sopa?.Name) ? sopa.Name : (naming != null ? naming.GetCorrected(field.Name) : field.Name);

                if (fieldName == name)
                {
                    var key = (objectType, fieldName, mbp : sopa);

                    if (_createdSetters.ContainsKey(key))
                    {
                        result = _createdSetters[key];
                    }
                    else
                    {
                        result = new PropOrField(field, sopa);
                        _createdSetters[key] = result;
                    }

                    return(result);
                }
            }

            return(PropOrField.Null);
        }