/// <summary>
        /// Update existing object from encoded values
        /// </summary>
        public static object UpdateInstance(object instance, Entry encoded, ICustomSerialization customSerialization)
        {
            var filtered = customSerialization.WriteFilter(instance.GetType(), encoded.SubEntries);

            foreach (var mapped in filtered)
            {
                var property            = mapped.Property;
                var propertyType        = mapped.Property.PropertyType;
                var doNotUpdateProperty = false;

                // Do not operate on faulty properties or read-only properties
                // For security reasons read the flag from the property again
                if (mapped.Entry?.Value.Type == EntryValueType.Exception || property.GetCustomAttribute <ReadOnlyAttribute>()?.IsReadOnly == true)
                {
                    continue;
                }

                // Try to assign value to the property
                var currentValue = mapped.Property.GetValue(instance);
                var value        = mapped.Entry == null
                    ? customSerialization.DefaultValue(property, currentValue)
                    : customSerialization.ConvertValue(propertyType, property, mapped.Entry, currentValue);

                // Value types, strings and streams do not need recursion
                if (ValueOrStringType(propertyType) || typeof(Stream).IsAssignableFrom(propertyType))
                {
                }
                // Update collection from entry
                else if (IsCollection(propertyType) && mapped.Entry != null)
                {
                    // Pick collection strategy
                    var strategy = CreateStrategy(value, currentValue, propertyType, customSerialization, mapped.Property, instance);
                    UpdateCollection(currentValue, mapped.Property.PropertyType, mapped.Property, mapped.Entry, strategy, customSerialization);
                    if (strategy is ArrayIListStrategy)
                    {
                        doNotUpdateProperty = true;
                    }
                }
                // Update class
                else if (propertyType.IsClass)
                {
                    UpdateInstance(value, mapped.Entry ?? new Entry(), customSerialization);
                }
                else
                {
                    throw new SerializationException($"Unsupported property {property.Name} on {instance.GetType().Name}!");
                }

                // Write new value to property
                if (property.CanWrite && !doNotUpdateProperty)
                {
                    mapped.Property.SetValue(instance, value);
                }
            }

            return(instance);
        }
        /// <summary>
        /// Convert encoded parameters to argument array for method invocation
        /// </summary>
        private static object[] ConvertArguments(MethodBase method, MethodEntry encodedMethod, ICustomSerialization customSerialization)
        {
            var parameters       = method.GetParameters();
            var arguments        = new object[parameters.Length];
            var parameterEntries = encodedMethod.Parameters.SubEntries;

            for (var i = 0; i < parameters.Length; i++)
            {
                var entry     = parameterEntries[i];
                var parameter = parameters[i];
                var paramType = parameter.ParameterType;
                var argument  = customSerialization.ConvertValue(paramType, parameter, entry, null);

                // Value types and strings do not need recursion
                if (ValueOrStringType(paramType))
                {
                }
                // Update collection from entry
                else if (argument is ICollection && entry != null)
                {
                    // Pick collection strategy
                    var strategy = CreateStrategy(argument, null, paramType, customSerialization);
                    UpdateCollection(null, paramType, parameter, entry, strategy, customSerialization);
                }
                // Update class
                else if (paramType.IsClass)
                {
                    if (entry == null)
                    {
                        UpdateInstance(argument, new Entry(), customSerialization);
                    }
                    else
                    {
                        UpdateInstance(argument, entry, customSerialization);
                    }
                }

                arguments[i] = argument;
            }

            return(arguments);
        }