コード例 #1
0
        /// <summary>
        /// Query if this is a collection of a mapped type
        /// </summary>
        /// <param name="sourceType"></param>
        /// <returns></returns>
        protected bool WillExpandCollection(Type sourceType)
        {
            var blindAssignment = BlindHandlers.Where(kv => kv.Key.IsAssignableFrom(sourceType)).Select(kv => kv.Value).FirstOrDefault();

            if (this.ExpandBlindObjects && blindAssignment != null)
            {
                return(false);
            }

            // figure out if this is an expandable list, instead
            // Is this a list of items we need to project?
            if (sourceType.GetTypeInfo().GetInterfaces()
                .Any(t => t.IsConstructedGenericType &&
                     t.GetGenericTypeDefinition() == typeof(IEnumerable <>)))
            {
                var interfaceType = sourceType.GetTypeInfo().GetInterfaces()
                                    .First(t => t.IsConstructedGenericType &&
                                           t.GetGenericTypeDefinition() == typeof(IEnumerable <>));

                // Verify that the generic parameter is something we would expand
                var genericType = interfaceType.GenericTypeArguments[0];
                if (this.WillExpandType(genericType))
                {
                    return(true);
                }
            }

            return(false);
        }
コード例 #2
0
        /// <summary>
        /// Query if this is a type that can be expanded with no projected type, i.e. blind
        /// </summary>
        /// <param name="sourceType"></param>
        /// <returns></returns>
        protected bool WillExpandBlind(Type sourceType)
        {
            if (!this.ExpandBlindObjects)
            {
                return(false);
            }

            var blindAssignment = BlindHandlers.Where(kv => kv.Key.IsAssignableFrom(sourceType)).Select(kv => kv.Value).FirstOrDefault();

            if (blindAssignment != null)
            {
                return(true);
            }

            return(!WillExpandDirect(sourceType) && // False if will expand direct or collection
                   !WillExpandCollection(sourceType) &&
                   sourceType.GetTypeInfo().IsClass && // False if a simple type
                   (!(sourceType.GetTypeInfo().GetInterfaces() // False if the object doesn't have an IEnumerable interface
                      .Any(t => t.IsConstructedGenericType &&
                           t.GetGenericTypeDefinition() == typeof(IEnumerable <>)))));
        }
コード例 #3
0
        /// <summary>
        /// Map a collection of mapped types
        /// </summary>
        /// <param name="originalValue"></param>
        /// <param name="destinationType"></param>
        /// <param name="context"></param>
        /// <param name="includes"></param>
        /// <param name="visited">todo: describe visited parameter on ExpandCollection</param>
        /// <returns></returns>
        protected IList ExpandCollection(object originalValue, Type destinationType, ContextType context, IEnumerable <PropertyReference> includes, HashSet <int> visited)
        {
            visited = UniqueVisit(originalValue, visited);

            var interfaceType = originalValue.GetType().GetTypeInfo().GetInterfaces()
                                .First(t => t.IsConstructedGenericType &&
                                       t.GetGenericTypeDefinition() == typeof(IEnumerable <>));

            // Verify that the generic parameter is something we would expand
            var genericType = interfaceType.GenericTypeArguments[0];

            // try to figure out the destination object type
            var destInterfaceType = destinationType.GetTypeInfo().GetInterfaces()
                                    .FirstOrDefault(t => t.IsConstructedGenericType &&
                                                    t.GetGenericTypeDefinition() == typeof(IEnumerable <>));


            Type expandedType;
            var  blindAssignment = BlindHandlers.Where(kv => kv.Key.IsAssignableFrom(genericType)).Select(kv => kv.Value).FirstOrDefault();

            if (destInterfaceType != null)
            {
                expandedType = destInterfaceType.GenericTypeArguments[0];
            }
            else if (this.Mappings.ContainsKey(genericType))
            {
                expandedType = this.Mappings[genericType].DefaultDestinationType;
            }
            else if (this.ExpandBlindObjects && blindAssignment != null)
            {
                expandedType = blindAssignment.Item1;
            }
            else
            {
                expandedType = typeof(Dictionary <string, object>);
            }

            // Ok, now we need to try and instantiate the destination type (if it is concrete) or take a guess
            // at a concrete type if it is an interface

            /// @TODO IList is an easy way of being able to add, but not all collections implement IList (like hashset)
            /// really we want to work with ICollection<T>, although for some reason ICollection (non-generic) doesn't have Add
            var instantiatedDestinationType = destinationType.CreateDefaultObject() as IList;

            if (instantiatedDestinationType == null)
            {
                var concreteType = typeof(List <>).MakeGenericType(expandedType);
                instantiatedDestinationType = concreteType.CreateDefaultObject() as IList;
            }

            // try to assign the data item by item
            foreach (var item in (IEnumerable)originalValue)
            {
                /// If authorization indicates this should not in fact be authorized, skip it
                if (!AuthorizeValue(originalValue, context, item))
                {
                    continue;
                }

                instantiatedDestinationType.Add(this.Expand(item, context, includes, visited, expandedType));
            }

            return(instantiatedDestinationType);
        }
コード例 #4
0
        /// <summary>
        /// Take a complex object, and transfer properties requested into a dictionary
        /// </summary>
        /// <param name="source"></param>
        /// <param name="context"></param>
        /// <param name="includes"></param>
        /// <param name="visited"></param>
        /// <returns></returns>
        protected object ExpandBlindObject(object source, ContextType context, IEnumerable <PropertyReference> includes, HashSet <int> visited)
        {
            visited = UniqueVisit(source, visited);

            Type sourceType = source.GetType();

            var blindAssignment = BlindHandlers.Where(kv => kv.Key.IsAssignableFrom(sourceType)).Select(kv => kv.Value).FirstOrDefault();

            if (blindAssignment != null)
            {
                return(blindAssignment.Item2(source, context));
            }

            includes = ConstructIncludes(includes, sourceType, null);

            if (!includes.Any())
            {
                return(null);
            }

            // Attempt to create a projection object we'll map the data into
            var destinationObject = new Dictionary <string, object>();

            MappingDefinition mappingDefinition = null;

            // Allow any actions to run ahead of mapping
            if (Mappings.ContainsKey(sourceType))
            {
                foreach (var action in Mappings[sourceType].BeforeExpansion)
                {
                    action(destinationObject, source, context);
                }

                mappingDefinition = Mappings[source.GetType()];
            }

            // Iterate over only the requested properties
            foreach (var propertyReference in includes)
            {
                string propertyName = propertyReference.PropertyName;

                if (mappingDefinition != null)
                {
                    var preparers = mappingDefinition.PrepareProperties;

                    // See if there's a propertyPreparer
                    if (preparers.ContainsKey(propertyName))
                    {
                        preparers[propertyName](destinationObject, null, source, context);
                    }
                }

                // Transform the input value as needed
                object valueToAssign = GetSourceValue(source, context, propertyName, mappingDefinition?.DefaultDestination()?.Translators);

                /// If authorization indicates this should not in fact be authorized, skip it
                if (!AuthorizeValue(source, context, valueToAssign))
                {
                    continue;
                }

                if (WillExpand(valueToAssign))
                {
                    valueToAssign = Expand(valueToAssign, context, propertyReference.Children, visited);
                }

                if (valueToAssign != null)
                {
                    destinationObject[propertyName] = valueToAssign;
                }
            }

            // Allow any actions to run after the mapping
            /// @Todo should this be in reverse order so we have a nested stack style FILO?
            if (Mappings.ContainsKey(sourceType))
            {
                foreach (var action in Mappings[sourceType].DefaultDestination().AfterExpansion)
                {
                    action(destinationObject, source, context);
                }
            }

            return(destinationObject);
        }