Esempio n. 1
0
        /// <summary>
        /// Returns true if object name should be ignored
        /// </summary>
        /// <param name="name">Property or field name</param>
        /// <param name="path">Full path to object</param>
        /// <param name="options">Comparison options</param>
        /// <param name="ignorePropertiesOrPaths">List of names or paths to ignore</param>
        /// <returns></returns>
        private bool IgnoreObjectName(string name, string path, MappingOptions options, ICollection <string> ignorePropertiesOrPaths, IEnumerable <CustomAttributeData> attributes = null)
        {
            var ignoreByNameOrPath = ignorePropertiesOrPaths?.Contains(name) == true || ignorePropertiesOrPaths?.Contains(path) == true;

            if (ignoreByNameOrPath)
            {
                return(true);
            }
#if FEATURE_CUSTOM_ATTRIBUTES
            if (attributes?.Any(x => !options.BitwiseHasFlag(MappingOptions.DisableIgnoreAttributes) && (_ignoreAttributes.Contains(x.AttributeType) || _ignoreAttributes.Contains(x.AttributeType.Name))) == true)
#else
            if (attributes?.Any(x => !options.BitwiseHasFlag(MappingOptions.DisableIgnoreAttributes) && (_ignoreAttributes.Contains(x.Constructor.DeclaringType) || _ignoreAttributes.Contains(x.Constructor.DeclaringType.Name))) == true)
#endif
            { return(true); }
            return(false);
        }
Esempio n. 2
0
        /// <summary>
        /// Initialize the mapper and scan for profiles
        /// </summary>
        /// <param name="options"></param>
        public static void Initialize(MappingOptions options = MappingOptions.ScanCurrentAssembly)
        {
            var type = typeof(Profile);

            if (options.BitwiseHasFlag(MappingOptions.ScanAllAssemblies))
            {
                // scan all known assemblies in the app domain
                Initialize(AppDomain.CurrentDomain.GetAssemblies());
            }
            else
            {
                // scan the current calling assembly for profiles
                Initialize(new Assembly[] { Assembly.GetCallingAssembly() });
            }
        }
Esempio n. 3
0
        /// <summary>
        /// (Recursive) Recursive function that inspects an object and its properties/fields and clones it
        /// </summary>
        /// <param name="sourceObject">The object to clone</param>
        /// <param name="destObject">The destination object</param>
        /// <param name="mapToType">The type to map to</param>
        /// <param name="currentDepth">The current tree depth</param>
        /// <param name="maxDepth">The max tree depth</param>
        /// <param name="options">The cloning options</param>
        /// <param name="objectTree">The object tree to prevent cyclical references</param>
        /// <param name="path">The current path being traversed</param>
        /// <param name="ignorePropertiesOrPaths">A list of properties or paths to ignore</param>
        /// <returns></returns>
        private object InspectAndMap <TSource, TDest>(object sourceObject, object destObject, ExtendedType mapToType, int currentDepth, int maxDepth, MappingOptions options, IDictionary <ObjectHashcode, object> objectTree, string path, ICollection <string> ignorePropertiesOrPaths = null)
        {
            if (IgnoreObjectName(null, path, options, ignorePropertiesOrPaths))
            {
                return(null);
            }

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

            // ensure we don't go too deep if specified
            if (maxDepth > 0 && currentDepth >= maxDepth)
            {
                return(null);
            }

            var sourceType = typeof(TSource).GetExtendedType();
            var destType   = typeof(TDest).GetExtendedType();

            if (ignorePropertiesOrPaths == null)
            {
                ignorePropertiesOrPaths = new List <string>();
            }

            // drop any objects we are ignoring by attribute
            if (mapToType.Attributes.Any(x => _ignoreAttributes.Contains(x)) && options.BitwiseHasFlag(MappingOptions.DisableIgnoreAttributes))
            {
                return(null);
            }

            // for delegate types, copy them by reference rather than returning null
            if (mapToType.IsDelegate)
            {
                return(sourceObject);
            }

            object newObject = destObject;

            // create a new empty object of the desired type
            if (newObject == null)
            {
                if (mapToType.IsArray)
                {
                    var length = 0;
                    if (mapToType.IsArray)
                    {
                        length = (sourceObject as Array).Length;
                    }
                    newObject = _objectFactory.CreateEmptyObject(mapToType.Type, length);
                }
                else if (mapToType.Type == typeof(string))
                {
                    // copy the item directly
                    newObject = Convert.ToString(sourceObject);
                    return(newObject);
                }
                else
                {
                    newObject = _objectFactory.CreateEmptyObject(mapToType.Type);
                }
            }

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

            // increment the current recursion depth
            currentDepth++;

            // construct a hashtable of objects we have already inspected (simple recursion loop preventer)
            // we use this hashcode method as it does not use any custom hashcode handlers the object might implement
            if (sourceObject != null && !mapToType.IsValueType)
            {
                var hashCode = System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(sourceObject);
                var key      = new ObjectHashcode(hashCode, newObject.GetType());
                if (objectTree.ContainsKey(key))
                {
                    return(objectTree[key]);
                }

                // ensure we can refer back to the reference for this object
                objectTree.Add(key, newObject);
            }

            var objectMapper = TypeRegistry.ObjectMappings
                               .FirstOrDefault(x => x.SourceObjectType == sourceType.Type &&
                                               x.DestinationObjectType == destType.Type);

            try
            {
                // clone a dictionary's key/values
                if (mapToType.IsDictionary && mapToType.IsGeneric)
                {
                    var    genericType = mapToType.Type.GetGenericArguments().ToList();
                    Type[] typeArgs    = { genericType[0], genericType[1] };

                    var listType      = typeof(Dictionary <,>).MakeGenericType(typeArgs);
                    var newDictionary = Activator.CreateInstance(listType) as IDictionary;
                    newObject = newDictionary;
                    var enumerator = (IDictionary)sourceObject;
                    foreach (DictionaryEntry item in enumerator)
                    {
                        var key   = InspectAndMap <TSource, TDest>(item.Key, null, item.Key.GetExtendedType(), currentDepth, maxDepth, options, objectTree, path, ignorePropertiesOrPaths);
                        var value = InspectAndMap <TSource, TDest>(item.Value, null, item.Value.GetExtendedType(), currentDepth, maxDepth, options, objectTree, path, ignorePropertiesOrPaths);
                        newDictionary.Add(key, value);
                    }
                    return(newObject);
                }

                // clone an enumerables' elements
                if (mapToType.IsEnumerable && mapToType.IsGeneric)
                {
                    var genericType         = mapToType.Type.GetGenericArguments().First();
                    var genericExtendedType = genericType.GetExtendedType();
                    var addMethod           = mapToType.Type.GetMethod("Add");
                    var enumerator          = (IEnumerable)sourceObject;
                    foreach (var item in enumerator)
                    {
                        var element = InspectAndMap <TSource, TDest>(item, null, genericExtendedType, currentDepth, maxDepth, options, objectTree, path, ignorePropertiesOrPaths);
                        addMethod.Invoke(newObject, new object[] { element });
                    }
                    return(newObject);
                }

                // clone an arrays' elements
                if (mapToType.IsArray)
                {
                    var sourceArray = sourceObject as Array;
                    var newArray    = newObject as Array;
                    newObject = newArray;
                    for (var i = 0; i < sourceArray.Length; i++)
                    {
                        var element    = sourceArray.GetValue(i);
                        var newElement = InspectAndMap <TSource, TDest>(element, null, mapToType.ElementType.GetExtendedType(), currentDepth, maxDepth, options, objectTree, path, ignorePropertiesOrPaths);
                        newArray.SetValue(newElement, i);
                    }
                    return(newArray);
                }

                var fields     = sourceObject.GetFields(FieldOptions.AllWritable);
                var properties = sourceObject.GetProperties(PropertyOptions.HasGetter);

                var rootPath = path;
                // clone and recurse fields
                if (newObject != null)
                {
                    foreach (var field in fields)
                    {
                        path = $"{rootPath}.{field.Name}";
                        if (IgnoreObjectName(field.Name, path, options, ignorePropertiesOrPaths, field.CustomAttributes))
                        {
                            continue;
                        }
                        // also check the property for ignore, if this is a auto-backing property
                        if (field.BackedProperty != null && IgnoreObjectName(field.BackedProperty.Name, $"{rootPath}.{field.BackedPropertyName}", options, ignorePropertiesOrPaths, field.BackedProperty.CustomAttributes))
                        {
                            continue;
                        }
                        newObject = MapField <TSource, TDest>(newObject, sourceObject, objectMapper, field, currentDepth, maxDepth, options, objectTree, path, ignorePropertiesOrPaths);
                    }
                    foreach (var property in properties)
                    {
                        path = $"{rootPath}.{property.Name}";
                        if (IgnoreObjectName(property.Name, path, options, ignorePropertiesOrPaths, property.CustomAttributes))
                        {
                            continue;
                        }

                        // also check the backing field for ignore, if this is a auto-backing property
                        if (property.BackingFieldName != null && IgnoreObjectName(property.BackingFieldName, $"{rootPath}.{property.BackingFieldName}", options, ignorePropertiesOrPaths, fields.FirstOrDefault(x => x.Name == property.BackingFieldName).CustomAttributes))
                        {
                            continue;
                        }

                        if (string.IsNullOrEmpty(property.BackingFieldName))
                        {
                            // map the property, it has no backing field so it's likely a method call
                            newObject = MapProperty <TSource, TDest>(newObject, sourceObject, objectMapper, property, currentDepth, maxDepth, options, objectTree, path, ignorePropertiesOrPaths);
                        }
                    }
                }

                return(newObject);
            }
            finally
            {
            }
        }