Example #1
0
        /// <summary>
        /// Performs a mapping operation from the <see cref="IEnumerable{IPublishedContent}"/> to a new <see cref="IEnumerable{Object}"/> instance
        /// </summary>
        /// <param name="content">The content to map</param>
        /// <param name="type">The <see cref="Type"/> of items to return.</param>
        /// <returns>
        /// The converted <see cref="IEnumerable{Object}"/>.
        /// </returns>
        public static IEnumerable <object> MapTo(this IEnumerable <IPublishedContent> content, Type type)
        {
            IEnumerable <object> typedItems = content.Select(x => x.MapTo(type));

            // We need to cast back here as nothing is strong typed anymore.
            return((IEnumerable <object>)EnumerableInvocations.Cast(type, typedItems));
        }
Example #2
0
        /// <inheritdoc/>
        public override object Map(IPublishedContent content, object value)
        {
            Type propType             = this.PropertyType;
            bool propTypeIsEnumerable = propType.IsEnumerableType();
            Type baseType             = propTypeIsEnumerable ? propType.GetEnumerableType() : propType;

            var types = (IEnumerable <Type>)ApplicationContext.Current.ApplicationCache.StaticCache.GetCacheItem("UmbMapperFactoryAttribute_ResolveTypes_" + baseType.AssemblyQualifiedName, () =>
            {
                // Workaround for http://issues.umbraco.org/issue/U4-9011
                if (baseType.Assembly.IsAppCodeAssembly())
                {
                    // This logic is taken from the core type finder so it should be performing the same checks
                    return(baseType.Assembly
                           .GetTypes()
                           .Where(t => baseType.IsAssignableFrom(t) &&
                                  t.IsClass &&
                                  !t.IsAbstract &&
                                  !t.IsSealed &&
                                  !t.IsNestedPrivate &&
                                  t.GetCustomAttribute <HideFromTypeFinderAttribute>(true) == null)
                           .ToArray());
                }

                return(PluginManagerInvocations.ResolveTypes(baseType));
            });

            // Check for IEnumerable<IPublishedContent> value
            if (value is IEnumerable <IPublishedContent> enumerableValue)
            {
                IEnumerable <object> items = enumerableValue.Select(x =>
                {
                    string typeName = this.ResolveTypeName(x);
                    Type type       = types.FirstOrDefault(y => y.Name.InvariantEquals(typeName));

                    return(type != null ? x.MapTo(type) : null);
                });

                return(EnumerableInvocations.Cast(baseType, items));
            }

            // Check for IPublishedContent value
            if (value is IPublishedContent ipublishedContentValue)
            {
                string typeName = this.ResolveTypeName(ipublishedContentValue);
                Type   type     = types.FirstOrDefault(y => y.Name.InvariantEquals(typeName));
                return(type != null?ipublishedContentValue.MapTo(type) : null);
            }

            // No other possible options
            return(this.DefaultValue);
        }
Example #3
0
        private static object SantizeValue(object value, PropertyMapInfo info)
        {
            bool propertyIsCastableEnumerable    = info.IsCastableEnumerableType;
            bool propertyIsConvertableEnumerable = info.IsConvertableEnumerableType;

            if (value != null)
            {
                Type valueType = value.GetType();
                if (valueType == info.PropertyType)
                {
                    return(value);
                }

                bool valueIsConvertableEnumerable = valueType.IsConvertableEnumerableType();

                // You cannot set an enumerable of type from an empty object array.
                // This should allow the casting back of IEnumerable<T> to an empty List<T> Collection<T> etc.
                // I cant think of any that don't have an empty constructor
                if (value.Equals(Enumerable.Empty <object>()) && propertyIsCastableEnumerable)
                {
                    Type typeArg = info.PropertyType.GetTypeInfo().GenericTypeArguments.First();
                    return(info.PropertyType.IsInterface ? EnumerableInvocations.Cast(typeArg, (IEnumerable)value) : info.PropertyType.GetInstance());
                }

                // Ensure only a single item is returned when requested.
                if (valueIsConvertableEnumerable && !propertyIsConvertableEnumerable)
                {
                    // Property is not enumerable, but value is, so grab first item
                    IEnumerator enumerator = ((IEnumerable)value).GetEnumerator();
                    return(enumerator.MoveNext() ? enumerator.Current : null);
                }

                // And now check for the reverse situation.
                if (!valueIsConvertableEnumerable && propertyIsConvertableEnumerable)
                {
                    var array = Array.CreateInstance(value.GetType(), 1);
                    array.SetValue(value, 0);
                    return(array);
                }
            }
            else
            {
                if (propertyIsCastableEnumerable)
                {
                    if (info.PropertyType.IsInterface && !info.IsEnumerableOfKeyValueType)
                    {
                        // Value is null, but property is enumerable interface, so return empty enumerable
                        return(EnumerableInvocations.Empty(info.PropertyType.GenericTypeArguments.First()));
                    }

                    // Concrete enumerables cannot be cast from Array so we create an instance and return it
                    // if we know it has an empty constructor.
                    ParameterInfo[] constructorParams = info.PropertyType.GetConstructorParameters();
                    if (constructorParams != null && constructorParams.Length == 0)
                    {
                        // Internally this uses Activator.CreateInstance which is heavily optimized.
                        return(info.PropertyType.GetInstance());
                    }
                }
            }

            return(value);
        }