/// <summary>
        ///   Converts the specified object into a dictionary.
        /// </summary>
        /// <param name="context">Serialization parameters, such as custom serializers and version number.</param>
        /// <param name="obj">Object to convert.</param>
        /// <returns>Dictionary representation of the specified object.</returns>
        public Dictionary<string, object> Serialize(DictionarySerializationContext context, object obj)
        {
            IDictionary dictionary = (IDictionary)obj;
            Type keyType = dictionary.GetType().GetGenericArguments()[0];
            if (keyType != typeof(string))
            {
                throw new SerializationException("Only dictionaries with string keys can be serialized right now");
            }

            Type valueType = dictionary.GetType().GetGenericArguments()[1];

            Dictionary<string, object> data = new Dictionary<string, object> { { DataType, valueType.FullName } };

            bool typeSealed = valueType.IsSealed();

            Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
            foreach (string key in dictionary.Keys)
            {
                object value = dictionary[key];
                object valueData = typeSealed || value == null ? value : new ValueWithType(value);
                keyValuePairs.Add(key, context.Serialize(valueData));
            }
            data.Add(DataPairs, keyValuePairs);

            return data;
        }
        /// <summary>
        ///   Serializes an object to a dictionary.
        /// </summary>
        /// <param name="context">Serialization parameters, such as custom serializers and version number.</param>
        /// <param name="obj">Object to serialize.</param>
        /// <returns>Dictionary which contains object data.</returns>
        public Dictionary<string, object> Serialize(DictionarySerializationContext context, object obj)
        {
            ValueWithType valueWithType = (ValueWithType)obj;

            Dictionary<string, object> data = new Dictionary<string, object>
                {
                    { DataValue, context.Serialize(valueWithType.Value) }
                };

            if (!context.IsRawSerializationPossible(valueWithType.Type))
            {
                data.Add(DataType, valueWithType.TypeFullName);
            }

            return data;
        }
        /// <summary>
        ///   Deserializes an object from a dictionary.
        /// </summary>
        /// <param name="context">Serialization parameters, such as custom serializers and version number.</param>
        /// <param name="data">Dictionary which contains the object data.</param>
        /// <returns>Deserialized object.</returns>
        public object Deserialize(DictionarySerializationContext context, Dictionary<string, object> data)
        {
            if (!data.ContainsKey(DataCount))
            {
                throw new ArgumentException(string.Format("List property not specified: {0}", DataCount));
            }

            if (!data.ContainsKey(DataType))
            {
                throw new ArgumentException(string.Format("List property not specified: {0}", DataType));
            }

            int count = Convert.ToInt32(data[DataCount]);
            string itemTypeString = (string)data[DataType];
            Type itemType = ReflectionUtils.FindType(itemTypeString);
            if (itemType == null)
            {
                throw new SerializationException(string.Format("Item type '{0}' not found", itemTypeString));
            }

            IList list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(itemType));

            bool typeSealed = itemType.IsSealed();
            for (int i = 0; i < count; i++)
            {
                object valueData = data[i.ToString(CultureInfo.InvariantCulture)];

                object value;
                if (valueData == null)
                {
                    value = null;
                }
                else if (typeSealed)
                {
                    value = context.Deserialize(itemType, valueData);
                }
                else
                {
                    ValueWithType valueWithType = context.Deserialize(typeof(ValueWithType), valueData) as ValueWithType;
                    value = valueWithType.Value;
                }

                list.Add(value);
            }

            return list;
        }
        /// <summary>
        ///   Deserializes an object from a dictionary.
        /// </summary>
        /// <param name="context">Serialization parameters, such as custom serializers and version number.</param>
        /// <param name="data">Dictionary which contains the object data.</param>
        /// <returns>Deserialized object.</returns>
        public object Deserialize(DictionarySerializationContext context, Dictionary<string, object> data)
        {
            ValueWithType valueWithType = new ValueWithType();

            object typeFullName;
            object value = data[DataValue];
            if (data.TryGetValue(DataType, out typeFullName))
            {
                valueWithType.TypeFullName = (string)typeFullName;
                Type type = valueWithType.Type;
                valueWithType.Value = context.Deserialize(type, value);
            }
            else
            {
                valueWithType.Value = value;
                valueWithType.Type = value.GetType();
            }

            return valueWithType;
        }
        /// <summary>
        ///   Deserializes an object from a dictionary.
        /// </summary>
        /// <param name="context">Serialization parameters, such as custom serializers and version number.</param>
        /// <param name="data">Dictionary which contains the object data.</param>
        /// <returns>Deserialized object.</returns>
        public object Deserialize(DictionarySerializationContext context, Dictionary<string, object> data)
        {
            int count = Convert.ToInt32(data[DataCount]);
            string itemTypeString = (string)data[DataType];
            Type itemType = ReflectionUtils.FindType(itemTypeString);
            if (itemType == null)
            {
                throw new SerializationException(string.Format("Item type '{0}' not found", itemTypeString));
            }

            Type genericType = typeof(Stack<>).MakeGenericType(itemType);
            object stack = Activator.CreateInstance(genericType);

            bool typeSealed = itemType.IsSealed();
            MethodInfo pushMethod = genericType.GetMethod("Push");
            for (int i = count - 1; i >= 0; --i)
            {
                object valueData = data[i.ToString(CultureInfo.InvariantCulture)];
                object value;
                if (valueData == null)
                {
                    value = null;
                }
                else if (typeSealed)
                {
                    value = context.Deserialize(itemType, valueData);
                }
                else
                {
                    ValueWithType valueWithType = context.Deserialize(typeof(ValueWithType), valueData) as ValueWithType;
                    value = valueWithType.Value;
                }

                pushMethod.Invoke(stack, new[] { value });
            }

            return stack;
        }
        /// <summary>
        ///   Serializes an object to a dictionary.
        /// </summary>
        /// <param name="context">Serialization parameters, such as custom serializers and version number.</param>
        /// <param name="obj">Object to serialize.</param>
        /// <returns>Dictionary which contains object data.</returns>
        public Dictionary<string, object> Serialize(DictionarySerializationContext context, object obj)
        {
            ICollection collection = (ICollection)obj;
            Type itemType = collection.GetType().GetGenericArguments()[0];

            Dictionary<string, object> data = new Dictionary<string, object>
                {
                    { DataCount, collection.Count },
                    { DataType, itemType.FullName }
                };

            bool typeSealed = itemType.IsSealed();

            int index = 0;
            foreach (object value in collection)
            {
                object valueData = typeSealed || value == null ? value : new ValueWithType(value);
                data.Add(index.ToString(CultureInfo.InvariantCulture), context.Serialize(valueData));
                ++index;
            }

            return data;
        }
        /// <summary>
        ///   Reads the object from the specified dictionary.
        /// </summary>
        /// <param name="context">Serialization parameters, such as custom serializers and version number.</param>
        /// <param name="data">Object to read.</param>
        /// <returns>Read object.</returns>
        public object Deserialize(DictionarySerializationContext context, Dictionary<string, object> data)
        {
            string itemTypeString = (string)data[DataType];
            Type itemType = ReflectionUtils.FindType(itemTypeString);
            if (itemType == null)
            {
                throw new SerializationException(string.Format("Item type '{0}' not found", itemTypeString));
            }

            Type genericType = typeof(Dictionary<,>).MakeGenericType(typeof(string), itemType);
            IDictionary dictionary = (IDictionary)Activator.CreateInstance(genericType);

            bool typeSealed = itemType.IsSealed();
            Dictionary<string, object> pairs = (Dictionary<string, object>)data[DataPairs];
            foreach (KeyValuePair<string, object> pair in pairs)
            {
                object valueData = pair.Value;
                object value;
                if (valueData == null)
                {
                    value = null;
                }
                else if (typeSealed)
                {
                    value = context.Deserialize(itemType, valueData);
                }
                else
                {
                    ValueWithType valueWithType = context.Deserialize(typeof(ValueWithType), valueData) as ValueWithType;
                    value = valueWithType.Value;
                }

                dictionary.Add(pair.Key, value);
            }

            return dictionary;
        }
        /// <summary>
        ///   Serializes an object to a dictionary.
        /// </summary>
        /// <param name="context">Serialization parameters, such as custom serializers and version number.</param>
        /// <param name="obj">Object to serialize.</param>
        /// <returns>Dictionary which contains object data.</returns>
        public Dictionary<string, object> Serialize(DictionarySerializationContext context, object obj)
        {
            IList list = (IList)obj;
            Type itemType = list.GetType().GetGenericArguments()[0];

            Dictionary<string, object> data = new Dictionary<string, object>
                {
                    { DataCount, list.Count },
                    { DataType, itemType.FullName }
                };

            bool typeSealed = itemType.IsSealed();
            for (int i = 0; i < list.Count; i++)
            {
                object value = list[i];
                object valueData = typeSealed || value == null ? value : new ValueWithType(value);

                string valueKey = i.ToString(CultureInfo.InvariantCulture);
                data.Add(valueKey, context.Serialize(valueData));
            }

            return data;
        }