/// <summary>
        /// Updates or adds a value with the specified <paramref name="name"/> in the <see cref="SerializationInfo"/>.
        /// </summary>
        /// <param name="info">The <see cref="SerializationInfo"/> to be updated.</param>
        /// <param name="name">The name of the entry to be updated or added.</param>
        /// <param name="value">The new value to be set.</param>
        /// <param name="type">The type of the value to be added. This parameter is optional.
        /// <br/>Default value: <see langword="null"/>.</param>
        /// <returns><see langword="true"/>&#160;if an update occurred (the <see cref="SerializationInfo"/> already contained an entry with the specified <paramref name="name"/>);
        /// <see langword="false"/>&#160;if the value has just been added as a new value.</returns>
        public static bool UpdateValue(this SerializationInfo info, string name, object value, Type type = null)
        {
            if (info == null)
            {
                Throw.ArgumentNullException(Argument.info);
            }
            if (name == null)
            {
                Throw.ArgumentNullException(Argument.name);
            }

            if (info.MemberCount == 0 || !info.ContainsName(name))
            {
                // that's why the method is generic: so we can specify a different type by specifying T explicitly
                info.AddValue(name, value, type ?? value?.GetType() ?? Reflector.ObjectType);
                return(false);
            }

            SerializationInfo clone = InitEmptyInstanceFrom(info);

            foreach (SerializationEntry entry in info)
            {
                if (entry.Name == name)
                {
                    info.AddValue(name, value, type ?? value?.GetType() ?? Reflector.ObjectType);
                }
                else
                {
                    clone.AddValue(entry.Name, entry.Value, entry.ObjectType);
                }
            }

            SerializationHelper.CopyFields(clone, info);
            return(true);
        }
        /// <summary>
        /// Restores target from source. Can be used for read-only properties when source object is already fully serialized.
        /// </summary>
        private static void CopyContent(object source, object target)
        {
            Debug.Assert(target != null && source != null && target.GetType() == source.GetType(), $"Same types are expected in {nameof(CopyContent)}.");

            // 1.) Array
            if (target is Array targetArray && source is Array sourceArray)
            {
                int[] lengths     = new int[sourceArray.Rank];
                int[] lowerBounds = new int[sourceArray.Rank];
                for (int i = 0; i < sourceArray.Rank; i++)
                {
                    lengths[i]     = sourceArray.GetLength(i);
                    lowerBounds[i] = sourceArray.GetLowerBound(i);
                }

                CheckArray(targetArray, lengths, lowerBounds, true);
                if (targetArray.GetType().GetElementType()?.IsPrimitive == true)
                {
                    Buffer.BlockCopy(sourceArray, 0, targetArray, 0, Buffer.ByteLength(sourceArray));
                }
                else if (lengths.Length == 1)
                {
                    Array.Copy(sourceArray, targetArray, sourceArray.Length);
                }
                else
                {
                    var indices = new ArrayIndexer(lengths, lowerBounds);
                    while (indices.MoveNext())
                    {
                        targetArray.SetValue(sourceArray.GetValue(indices.Current), indices.Current);
                    }
                }

                return;
            }

            // 2.) non-array: every fields (here we don't know how was the instance serialized but we have a deserialized source)
            SerializationHelper.CopyFields(source, target);
        }
        /// <summary>
        /// Removes a value of the specified <paramref name="name"/> from the <see cref="SerializationInfo"/>.
        /// </summary>
        /// <param name="info">The <see cref="SerializationInfo"/> to remove the value from.</param>
        /// <param name="name">The name of the entry to remove.</param>
        /// <returns><see langword="true"/>&#160;if an entry with the specified name existed in the <see cref="SerializationInfo"/>
        /// and has been removed; otherwise, <see langword="false"/>.</returns>
        public static bool RemoveValue(this SerializationInfo info, string name)
        {
            if (info == null)
            {
                Throw.ArgumentNullException(Argument.info);
            }
            if (name == null)
            {
                Throw.ArgumentNullException(Argument.name);
            }

            if (info.MemberCount == 0)
            {
                return(false);
            }
            SerializationInfo clone = InitEmptyInstanceFrom(info);
            bool removed            = false;

            foreach (SerializationEntry entry in info)
            {
                if (entry.Name == name)
                {
                    removed = true;
                }
                else
                {
                    clone.AddValue(entry.Name, entry.Value, entry.ObjectType);
                }
            }

            if (!removed)
            {
                return(false);
            }

            SerializationHelper.CopyFields(clone, info);
            return(true);
        }
        /// <summary>
        /// Replaces a value with the specified old and new names in the <see cref="SerializationInfo"/>.
        /// </summary>
        /// <param name="info">The <see cref="SerializationInfo"/> to be updated.</param>
        /// <param name="oldName">The name of the entry to be removed.</param>
        /// <param name="newName">The name of the entry to be added.</param>
        /// <param name="value">The new value to be set.</param>
        /// <param name="type">The type of the value to be added. This parameter is optional.
        /// <br/>Default value: <see langword="null"/>.</param>
        /// <returns><see langword="true"/>&#160;if an entry with the specified old name existed in the <see cref="SerializationInfo"/>
        /// and the replace has been performed; otherwise, <see langword="false"/>.</returns>
        public static bool ReplaceValue(this SerializationInfo info, string oldName, string newName, object value, Type type = null)
        {
            if (info == null)
            {
                Throw.ArgumentNullException(Argument.info);
            }
            if (oldName == null)
            {
                Throw.ArgumentNullException(Argument.oldName);
            }
            if (newName == null)
            {
                Throw.ArgumentNullException(Argument.newName);
            }

            if (info.MemberCount == 0 || !info.ContainsName(oldName))
            {
                return(false);
            }

            SerializationInfo clone = InitEmptyInstanceFrom(info);

            foreach (SerializationEntry entry in info)
            {
                if (entry.Name == oldName)
                {
                    clone.AddValue(newName, value, type ?? value?.GetType() ?? Reflector.ObjectType);
                }
                else
                {
                    clone.AddValue(entry.Name, entry.Value, entry.ObjectType);
                }
            }

            SerializationHelper.CopyFields(clone, info);
            return(true);
        }