/// <summary>
        /// Returns the raw value for the given type and property.
        /// </summary>
        /// <param name="content">The <see cref="IPublishedContent"/> to convert.</param>
        /// <param name="culture">The <see cref="CultureInfo"/></param>
        /// <param name="propertyInfo">The <see cref="PropertyInfo"/> property info associated with the type.</param>
        /// <returns>The <see cref="object"/> representing the Umbraco value.</returns>
        /// <param name="instance">The instance to assign the value to.</param>
        private static object GetRawValue(
            IPublishedContent content,
            CultureInfo culture,
            PropertyInfo propertyInfo,
            object instance)
        {
            // Check the property for an associated value attribute, otherwise fall-back on expected behaviour.
            var valueAttr = propertyInfo.GetCustomAttribute <DittoValueResolverAttribute>(true)
                            ?? new UmbracoPropertyAttribute();

            // TODO: Only create one context and share between GetRawValue and SetTypedValue?
            var descriptor = TypeDescriptor.GetProperties(instance)[propertyInfo.Name];
            var context    = new PublishedContentContext(content, descriptor);

            // Time custom value-resolver.
            using (DisposableTimer.DebugDuration <object>(string.Format("Custom ValueResolver ({0}, {1})", content.Id, propertyInfo.Name), "Complete"))
            {
                // Get the value from the custom attribute.
                // TODO: Cache these?
                var resolver = (DittoValueResolver)valueAttr.ResolverType.GetInstance();
                return(resolver.ResolveValue(context, valueAttr, culture));
            }
        }
        /// <summary>
        /// Returns an object representing the given <see cref="Type"/>.
        /// </summary>
        /// <param name="content">
        /// The <see cref="IPublishedContent"/> to convert.
        /// </param>
        /// <param name="type">
        /// The <see cref="Type"/> of items to return.
        /// </param>
        /// <returns>
        /// The converted <see cref="Object"/> as the given type.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        /// Thrown if the given type has invalid constructors.
        /// </exception>
        private static object GetTypedProperty(
            IPublishedContent content,
            Type type,
            CultureInfo culture = null)
        {
            // Check if the culture has been set, otherwise use from Umbraco.
            if (culture == null)
            {
                culture = UmbracoContext.Current.PublishedContentRequest.Culture;
            }

            // Get the default constructor, parameters and create an instance of the type.
            // Try and return from the cache first. TryGetValue is faster than GetOrAdd.
            ParameterInfo[] constructorParams;
            ConstructorCache.TryGetValue(type, out constructorParams);

            if (constructorParams == null)
            {
                var constructor = type.GetConstructors().OrderBy(x => x.GetParameters().Length).First();
                constructorParams = constructor.GetParameters();
                ConstructorCache.TryAdd(type, constructorParams);
            }

            object instance;

            if (constructorParams.Length == 0)
            {
                // Internally this uses Activator.CreateInstance which is heavily optimized.
                instance = type.GetInstance();
            }
            else if (constructorParams.Length == 1 & constructorParams[0].ParameterType == typeof(IPublishedContent))
            {
                // This extension method is about 7x faster than the native implementation.
                instance = type.GetInstance(content);
            }
            else
            {
                throw new InvalidOperationException("Type {0} has invalid constructor parameters");
            }

            // Collect all the properties of the given type and loop through writable ones.
            PropertyInfo[] properties;
            PropertyCache.TryGetValue(type, out properties);
            if (properties == null)
            {
                properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.CanWrite).ToArray();
                PropertyCache.TryAdd(type, properties);
            }

            var contentType = content.GetType();

            foreach (var propertyInfo in properties)
            {
                using (DisposableTimer.DebugDuration(type, string.Format("ForEach Property ({1} {0})", propertyInfo.Name, content.Id), "Complete"))
                {
                    // Check for the ignore attribute.
                    var ignoreAttr = propertyInfo.GetCustomAttribute <DittoIgnoreAttribute>();
                    if (ignoreAttr != null)
                    {
                        continue;
                    }

                    var    umbracoPropertyName    = propertyInfo.Name;
                    var    altUmbracoPropertyName = string.Empty;
                    var    recursive    = false;
                    object defaultValue = null;

                    var umbracoPropertyAttr = propertyInfo.GetCustomAttribute <UmbracoPropertyAttribute>();
                    if (umbracoPropertyAttr != null)
                    {
                        umbracoPropertyName    = umbracoPropertyAttr.PropertyName;
                        altUmbracoPropertyName = umbracoPropertyAttr.AltPropertyName;
                        recursive    = umbracoPropertyAttr.Recursive;
                        defaultValue = umbracoPropertyAttr.DefaultValue;
                    }

                    // Try fetching the value.
                    var    contentProperty = contentType.GetProperty(umbracoPropertyName);
                    object propertyValue   = contentProperty != null
                                            ? contentProperty.GetValue(content, null)
                                            : content.GetPropertyValue(umbracoPropertyName, recursive);

                    // Try fetching the alt value.
                    if ((propertyValue == null || propertyValue.ToString().IsNullOrWhiteSpace()) &&
                        !string.IsNullOrWhiteSpace(altUmbracoPropertyName))
                    {
                        contentProperty = contentType.GetProperty(altUmbracoPropertyName);
                        propertyValue   = contentProperty != null
                                            ? contentProperty.GetValue(content, null)
                                            : content.GetPropertyValue(altUmbracoPropertyName, recursive);
                    }

                    // Try setting the default value.
                    if ((propertyValue == null || propertyValue.ToString().IsNullOrWhiteSpace()) &&
                        defaultValue != null)
                    {
                        propertyValue = defaultValue;
                    }

                    // Process the value.
                    if (propertyValue != null)
                    {
                        var propertyType     = propertyInfo.PropertyType;
                        var typeInfo         = propertyType.GetTypeInfo();
                        var isEnumerableType = propertyType.IsEnumerableType() && typeInfo.GenericTypeArguments.Any();

                        // Try any custom type converters first.
                        // 1: Check the property.
                        // 2: Check any type arguments in generic enumerable types.
                        // 3: Check the type itself.
                        var converterAttribute =
                            propertyInfo.GetCustomAttribute <TypeConverterAttribute>()
                            ?? (isEnumerableType ? typeInfo.GenericTypeArguments.First().GetCustomAttribute <TypeConverterAttribute>(true)
                                                 : propertyType.GetCustomAttribute <TypeConverterAttribute>(true));

                        if (converterAttribute != null)
                        {
                            if (converterAttribute.ConverterTypeName != null)
                            {
                                // Time custom conversions.
                                using (DisposableTimer.DebugDuration(type, string.Format("Custom TypeConverter ({0}, {1})", content.Id, propertyInfo.Name), "Complete"))
                                {
                                    // Get the custom converter from the attribute and attempt to convert.
                                    var toConvert = Type.GetType(converterAttribute.ConverterTypeName);
                                    if (toConvert != null)
                                    {
                                        var converter = DependencyResolver.Current.GetService(toConvert) as TypeConverter;
                                        if (converter != null && converter.CanConvertFrom(propertyValue.GetType()))
                                        {
                                            // Create context to pass to converter implementations.
                                            // This contains the IPublishedContent and the currently converting property descriptor.
                                            var    descriptor = TypeDescriptor.GetProperties(instance)[propertyInfo.Name];
                                            var    context    = new PublishedContentContext(content, descriptor);
                                            object converted  = converter.ConvertFrom(context, culture, propertyValue);

                                            // Handle Typeconverters returning single objects when we want an IEnumerable.
                                            // Use case: Someone selects a folder of images rather than a single image with the media picker.
                                            if (isEnumerableType)
                                            {
                                                var parameterType = typeInfo.GenericTypeArguments.First();

                                                // Some converters return an IEnumerable so we check again.
                                                if (!converted.GetType().IsEnumerableType())
                                                {
                                                    // Generate a method using 'Cast' to convert the type back to IEnumerable<T>.
                                                    MethodInfo castMethod = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(parameterType);
                                                    object     enumerablePropertyValue = castMethod.Invoke(null, new object[] { converted.YieldSingleItem() });
                                                    propertyInfo.SetValue(instance, enumerablePropertyValue, null);
                                                }
                                                else
                                                {
                                                    propertyInfo.SetValue(instance, converted, null);
                                                }
                                            }
                                            else
                                            {
                                                propertyInfo.SetValue(instance, converted, null);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else if (propertyInfo.PropertyType == typeof(HtmlString))
                        {
                            // Handle Html strings so we don't have to set the attribute.
                            HtmlStringConverter converter = new HtmlStringConverter();
                            if (converter.CanConvertFrom(propertyValue.GetType()))
                            {
                                // This contains the IPublishedContent and the currently converting property descriptor.
                                var descriptor = TypeDescriptor.GetProperties(instance)[propertyInfo.Name];
                                var context    = new PublishedContentContext(content, descriptor);
                                propertyInfo.SetValue(instance, converter.ConvertFrom(context, culture, propertyValue), null);
                            }
                        }
                        else if (propertyInfo.PropertyType.IsInstanceOfType(propertyValue))
                        {
                            // Simple types
                            propertyInfo.SetValue(instance, propertyValue, null);
                        }
                        else
                        {
                            using (DisposableTimer.DebugDuration(type, string.Format("TypeConverter ({0}, {1})", content.Id, propertyInfo.Name), "Complete"))
                            {
                                var convert = propertyValue.TryConvertTo(propertyInfo.PropertyType);
                                if (convert.Success)
                                {
                                    propertyInfo.SetValue(instance, convert.Result, null);
                                }
                            }
                        }
                    }
                }
            }

            return(instance);
        }
        /// <summary>
        /// Set the typed value to the given instance.
        /// </summary>
        /// <param name="content">The <see cref="IPublishedContent"/> to convert.</param>
        /// <param name="culture">The <see cref="CultureInfo"/></param>
        /// <param name="propertyInfo">The <see cref="PropertyInfo"/> property info associated with the type.</param>
        /// <param name="propertyValue">The property value.</param>
        /// <param name="instance">The instance to assign the value to.</param>
        /// <returns>The strong typed converted value for the given property.</returns>
        private static object GetTypedValue(
            IPublishedContent content,
            CultureInfo culture,
            PropertyInfo propertyInfo,
            object propertyValue,
            object instance)
        {
            // Process the value.
            object result       = null;
            var    propertyType = propertyInfo.PropertyType;
            var    typeInfo     = propertyType.GetTypeInfo();

            // This should return false against typeof(string) also.
            var propertyIsEnumerableType = propertyType.IsEnumerableType() && typeInfo.GenericTypeArguments.Any();

            // Try any custom type converters first.
            // 1: Check the property.
            // 2: Check any type arguments in generic enumerable types.
            // 3: Check the type itself.
            var converterAttribute =
                propertyInfo.GetCustomAttribute <TypeConverterAttribute>()
                ?? (propertyIsEnumerableType ? typeInfo.GenericTypeArguments.First().GetCustomAttribute <TypeConverterAttribute>(true)
                                             : propertyType.GetCustomAttribute <TypeConverterAttribute>(true));

            if (converterAttribute != null && converterAttribute.ConverterTypeName != null)
            {
                // Time custom conversions.
                using (DisposableTimer.DebugDuration <object>(string.Format("Custom TypeConverter ({0}, {1})", content.Id, propertyInfo.Name), "Complete"))
                {
                    // Get the custom converter from the attribute and attempt to convert.
                    var converterType = Type.GetType(converterAttribute.ConverterTypeName);
                    if (converterType != null)
                    {
                        var converter = converterType.GetDependencyResolvedInstance() as TypeConverter;

                        if (converter != null)
                        {
                            // Create context to pass to converter implementations.
                            // This contains the IPublishedContent and the currently converting property descriptor.
                            var descriptor = TypeDescriptor.GetProperties(instance)[propertyInfo.Name];
                            var context    = new PublishedContentContext(content, descriptor);

                            Type propertyValueType = null;
                            if (propertyValue != null)
                            {
                                propertyValueType = propertyValue.GetType();
                            }

                            // We're deliberately passing null.
                            // ReSharper disable once AssignNullToNotNullAttribute
                            if (converter.CanConvertFrom(context, propertyValueType))
                            {
                                object converted = converter.ConvertFrom(context, culture, propertyValue);

                                if (converted != null)
                                {
                                    // Handle Typeconverters returning single objects when we want an IEnumerable.
                                    // Use case: Someone selects a folder of images rather than a single image with the media picker.
                                    var convertedType = converted.GetType();

                                    if (propertyIsEnumerableType)
                                    {
                                        var parameterType = typeInfo.GenericTypeArguments.First();

                                        // Some converters return an IEnumerable so we check again.
                                        if (!convertedType.IsEnumerableType())
                                        {
                                            // Using 'Cast' to convert the type back to IEnumerable<T>.
                                            object enumerablePropertyValue = EnumerableInvocations.Cast(
                                                parameterType,
                                                converted.YieldSingleItem());

                                            result = enumerablePropertyValue;
                                        }
                                        else
                                        {
                                            // Nothing is strong typed anymore.
                                            result = EnumerableInvocations.Cast(parameterType, (IEnumerable)converted);
                                        }
                                    }
                                    else
                                    {
                                        // Return single expected items from converters returning an IEnumerable.
                                        // Check for string.
                                        if (convertedType.IsEnumerableType() && convertedType.GenericTypeArguments.Any())
                                        {
                                            // Use 'FirstOrDefault' to convert the type back to T.
                                            result = EnumerableInvocations.FirstOrDefault(propertyType, (IEnumerable)converted);
                                        }
                                        else
                                        {
                                            result = converted;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else if (propertyInfo.PropertyType == typeof(HtmlString))
            {
                // Handle Html strings so we don't have to set the attribute.
                var converterType = typeof(DittoHtmlStringConverter);
                var converter     = converterType.GetDependencyResolvedInstance() as TypeConverter;

                if (converter != null)
                {
                    // This contains the IPublishedContent and the currently converting property descriptor.
                    var descriptor = TypeDescriptor.GetProperties(instance)[propertyInfo.Name];
                    var context    = new PublishedContentContext(content, descriptor);

                    Type propertyValueType = null;
                    if (propertyValue != null)
                    {
                        propertyValueType = propertyValue.GetType();
                    }

                    // We're deliberately passing null.
                    // ReSharper disable once AssignNullToNotNullAttribute
                    if (converter.CanConvertFrom(context, propertyValueType))
                    {
                        result = converter.ConvertFrom(context, culture, propertyValue);
                    }
                }
            }
            else if (propertyInfo.PropertyType.IsInstanceOfType(propertyValue))
            {
                // Simple types
                result = propertyValue;
            }
            else
            {
                using (DisposableTimer.DebugDuration <object>(string.Format("TypeConverter ({0}, {1})", content.Id, propertyInfo.Name), "Complete"))
                {
                    var convert = propertyValue.TryConvertTo(propertyInfo.PropertyType);
                    if (convert.Success)
                    {
                        result = convert.Result;
                    }
                }
            }

            return(result);
        }