/// <summary>
        /// Convert object to MetadataModel instance.
        /// </summary>
        /// <param name="source">Object to convert.</param>
        /// <param name="sourceType">The type of source object.</param>
        /// <param name="name">Name for result MetadataModel.</param>
        /// <returns>Instance of MetadataModel.</returns>
        public static MetadataModel ToMetadataModel(this object source, Type sourceType, string name = null)
        {
            if (source == null)
            {
                return(MetadataModel.GetEmptyMetadataModel());
            }

            if (sourceType.Equals(typeof(MetadataModel)))
            {
                return((source as MetadataModel) ?? MetadataModel.GetEmptyMetadataModel());
            }

            MetadataModel result = new MetadataModel {
                Name = name ?? sourceType.FullName.Replace('.', '_')
            };

            if (XmlConverter.CanConvert(sourceType))
            {
                result.IsValueType = true;

                try
                {
                    result.Value = XmlConverter.ToString(source);
                }
                catch
                {
                    result.Value = null;
                }
            }
            else if (source is XmlElement)
            {
                result.IsValueType = true;

                try
                {
                    result.Value = (source as XmlElement).OuterXml;
                }
                catch
                {
                    result.Value = null;
                }
            }
            else
            {
                result.IsValueType = false;

                if (CanEnumerable(sourceType))
                {
                    if (source != null)
                    {
                        foreach (var item in source as IEnumerable)
                        {
                            result.AddProperty(item.ToMetadataModel(item.GetType()));
                        }
                    }
                    else
                    {
                        Type elementType = null;

                        if (IsDictionary(sourceType))
                        {
                            elementType = typeof(KeyValuePair <,>).MakeGenericType(sourceType.GetGenericArguments());
                        }
                        else
                        {
                            elementType = sourceType.IsArray ? sourceType.GetElementType() : sourceType.GetGenericArguments()[0];
                        }

                        result.AddProperty(((object)null).ToMetadataModel(elementType));
                    }
                }
                else
                {
                    foreach (var item in sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead))
                    {
                        try
                        {
                            object itemValue = source == null ? null : item.GetValue(source, null);

                            result.AddProperty(itemValue.ToMetadataModel(item.PropertyType, item.Name));
                        }
                        catch
                        {
                        }
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// Gets the property names internal.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="propertyAccess">The property access.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <returns>List of properties.</returns>
        private static List <KeyValuePair <string, Type> > GetPropertyNamesInternal(Type source, Func <PropertyInfo, bool> propertyAccess, string propertyName = null)
        {
            List <KeyValuePair <string, Type> > result = new List <KeyValuePair <string, Type> >();

            if (source == typeof(void) ||
                XmlConverter.CanConvert(source) ||
                source == typeof(XmlElement))
            {
                if (!string.IsNullOrWhiteSpace(propertyName))
                {
                    result.Add(new KeyValuePair <string, Type>(propertyName, source));
                }

                return(result);
            }
            else
            {
                if (CanEnumerable(source))
                {
                    Type elementType = source.IsArray ? source.GetElementType() : source.GetGenericArguments()[0];

                    result.AddRange(GetPropertyNamesInternal(elementType, propertyAccess, propertyName + "[0]"));
                }
                else
                {
                    foreach (var item in source.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(propertyAccess))
                    {
                        Type type = item.PropertyType;

                        if (type == source)
                        {
                            continue;
                        }
                        else if (CanEnumerable(type))
                        {
                            Type elementType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0];

                            if (elementType == source)
                            {
                                continue;
                            }
                        }

                        string name;

                        if (string.IsNullOrWhiteSpace(propertyName))
                        {
                            name = item.Name;
                        }
                        else
                        {
                            name = propertyName + "." + item.Name;
                        }

                        result.AddRange(GetPropertyNamesInternal(type, propertyAccess, name));
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// Convert MetadataModel instance to object.
        /// </summary>
        /// <param name="source">MetadataModel to convert.</param>
        /// <param name="targetType">The type of return object.</param>
        /// <returns>The target type object.</returns>
        public static object ToObject(this MetadataModel source, Type targetType)
        {
            if (source.IsNull)
            {
                return(null);
            }

            if (targetType.Equals(typeof(MetadataModel)))
            {
                return(source);
            }

            if (XmlConverter.CanConvert(targetType))
            {
                if (source.IsValueType && source.Value != null)
                {
                    return(XmlConverter.ToObject(source.Value, targetType));
                }
                else
                {
                    return(null);
                }
            }
            else if (targetType.Equals(typeof(XmlElement)))
            {
                if (source.IsValueType && source.Value != null)
                {
                    try
                    {
                        XmlDocument xmlDocument = new XmlDocument();
                        xmlDocument.LoadXml(source.Value);
                        return(xmlDocument.DocumentElement);
                    }
                    catch
                    {
                        return(null);
                    }
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                if (CanEnumerable(targetType))
                {
                    if (IsDictionary(targetType))
                    {
                        IDictionary propertyDict = (IDictionary)Activator.CreateInstance(targetType, true);

                        foreach (var propertyItem in source.Properties)
                        {
                            if (!propertyItem.IsNull)
                            {
                                try
                                {
                                    var key = propertyItem[0].ToObject(targetType.GetGenericArguments()[0]);

                                    if (key != null)
                                    {
                                        var value = propertyItem[1].ToObject(targetType.GetGenericArguments()[1]);

                                        propertyDict.Add(key, value);
                                    }
                                }
                                catch
                                {
                                }
                            }
                        }

                        return(propertyDict.Count > 0 ? propertyDict : (IDictionary)null);
                    }
                    else
                    {
                        if (targetType.IsArray)
                        {
                            Type elementType = targetType.GetElementType();

                            IList resultTemp = new List <dynamic>();

                            foreach (var propertyItem in source.Properties)
                            {
                                if (!propertyItem.IsNull)
                                {
                                    try
                                    {
                                        var listItem = propertyItem.ToObject(elementType);

                                        if (listItem != null)
                                        {
                                            resultTemp.Add(listItem);
                                        }
                                    }
                                    catch
                                    {
                                    }
                                }
                            }

                            if (resultTemp.Count > 0)
                            {
                                Array result = Array.CreateInstance(elementType, resultTemp.Count);

                                resultTemp.CopyTo(result, 0);

                                return(result);
                            }
                            else
                            {
                                return((IList)null);
                            }
                        }
                        else
                        {
                            Type elementType = targetType.GetGenericArguments()[0];

                            IList result = (IList)Activator.CreateInstance(targetType, true);

                            foreach (var propertyItem in source.Properties)
                            {
                                if (!propertyItem.IsNull)
                                {
                                    try
                                    {
                                        var listItem = propertyItem.ToObject(elementType);

                                        if (listItem != null)
                                        {
                                            result.Add(listItem);
                                        }
                                    }
                                    catch
                                    {
                                    }
                                }
                            }

                            return(result.Count > 0 ? result : (IList)null);
                        }
                    }
                }
                else
                {
                    object result = null;

                    try
                    {
                        result = Activator.CreateInstance(targetType, true);
                    }
                    catch
                    {
                        try
                        {
                            result = FormatterServices.GetUninitializedObject(targetType);
                        }
                        catch
                        {
                        }
                    }

                    if (result == null)
                    {
                        return(result);
                    }

                    bool isNullReturn = true;

                    foreach (var item in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(i => i.CanWrite))
                    {
                        try
                        {
                            if (source.HasProperty(item.Name))
                            {
                                var sourceItem = source.GetProperty(item.Name);

                                var sourceItemValue = sourceItem.ToObject(item.PropertyType);

                                item.SetValue(result, sourceItemValue, null);

                                if (sourceItemValue != null)
                                {
                                    isNullReturn = false;
                                }
                            }
                        }
                        catch
                        {
                        }
                    }

                    return(isNullReturn ? null : result);
                }
            }
        }