/// <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)); }
/// <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); }
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); }