/// <summary>
        /// Clears all mappings and compiled caches.
        /// </summary>
        public void Clear()
        {
            Lock.EnterWriteLock();

            try
            {
                MappingRows.Clear();
                CompiledCache.Clear();
            }
            finally
            {
                Lock.ExitWriteLock();
            }
        }
        /// <summary>
        /// Determines if a mapping exists in this <see cref="MapperContext"/>.
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Contains(Mapping item)
        {
            var hash = Mapping.ComputeHash(item);

            Lock.EnterReadLock();

            try
            {
                return(MappingRows.ContainsKey(hash));
            }
            finally
            {
                Lock.ExitReadLock();
            }
        }
        /// <summary>
        /// Determines if a mapping exists in this <see cref="MapperContext"/>.
        /// </summary>
        /// <param name="destinationType"></param>
        /// <param name="sourceType"></param>
        /// <returns></returns>
        public bool Contains(Type destinationType, Type sourceType)
        {
            var hash = Mapping.ComputeHash(destinationType, sourceType);

            Lock.EnterReadLock();

            try
            {
                return(MappingRows.ContainsKey(hash));
            }
            finally
            {
                Lock.ExitReadLock();
            }
        }
        /// <summary>
        /// Returns the <see cref="Mapping"/> using given destinationType and sourceType.
        /// </summary>
        /// <param name="destinationType"></param>
        /// <param name="sourceType"></param>
        /// <param name="mapping"></param>
        /// <returns>A value indicating that value is found or not.</returns>
        public bool TryGetMapping(Type destinationType, Type sourceType, out Mapping mapping)
        {
            var hash = Mapping.ComputeHash(destinationType, sourceType);

            Lock.EnterReadLock();

            try
            {
                return(MappingRows.TryGetValue(hash, out mapping));
            }
            finally
            {
                Lock.ExitReadLock();
            }
        }
        /// <summary>
        /// Adds a mapping to <see cref="MapperContext"/>.
        /// </summary>
        /// <param name="item"></param>
        public void Add(Mapping item)
        {
            var hash = Mapping.ComputeHash(item);

            Lock.EnterWriteLock();

            try
            {
                MappingRows.Add(hash, item);
                CompiledCache.Miss(hash);
            }
            finally
            {
                Lock.ExitWriteLock();
            }
        }
        /// <summary>
        /// Removes a mapping (and it's compiled cache) from <see cref="MapperContext"/>.
        /// </summary>
        /// <param name="destinationType"></param>
        /// <param name="sourceType"></param>
        /// <returns></returns>
        public bool Remove(Type destinationType, Type sourceType)
        {
            var hash = Mapping.ComputeHash(destinationType, sourceType);

            Lock.EnterWriteLock();

            try
            {
                var result = MappingRows.Remove(hash);
                CompiledCache.Miss(hash);
                return(result);
            }
            finally
            {
                Lock.ExitWriteLock();
            }
        }
        /// <summary>
        /// Removes a mapping (and it's compiled cache) from <see cref="MapperContext"/>.
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Remove(Mapping item)
        {
            var hash = Mapping.ComputeHash(item);

            Lock.EnterWriteLock();

            try
            {
                var result = MappingRows.Remove(hash);
                CompiledCache.Miss(hash);
                return(result);
            }
            finally
            {
                Lock.ExitWriteLock();
            }
        }
        public bool TryGetMappingAndCompiledInfo(Type destinationType, Type sourceType, out Mapping mapping,
                                                 out MappingCompiledInfo mappingCompiledInfo)
        {
            var hash = Mapping.ComputeHash(destinationType, sourceType);

            Lock.EnterReadLock();

            try
            {
                var result = MappingRows.TryGetValue(hash, out mapping);
                CompiledCache.TryGetValue(hash, out mappingCompiledInfo);
                return(result);
            }
            finally
            {
                Lock.ExitReadLock();
            }
        }
        /// <summary>
        /// Adds a range of mappings to <see cref="MapperContext"/>.
        /// </summary>
        /// <param name="items"></param>
        public void AddRange(IEnumerable <Mapping> items)
        {
            var hashes = new List <int>();

            Lock.EnterWriteLock();

            try
            {
                foreach (var item in items)
                {
                    var hash = Mapping.ComputeHash(item);
                    MappingRows.Add(hash, item);
                    hashes.Add(hash);
                }

                CompiledCache.MissAll(hashes);
            }
            finally
            {
                Lock.ExitWriteLock();
            }
        }
        /// <summary>
        /// Merges another <see cref="MapperContext"/> with this instance of <see cref="MapperContext"/>.
        /// </summary>
        /// <remarks>
        /// This will modify current object.
        /// </remarks>
        /// <param name="mapperContext"></param>
        /// <param name="mergeBehavior"></param>
        /// <exception cref="InvalidOperationException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public void MergeWith(MapperContext mapperContext,
                              MapperContextMergeBehavior mergeBehavior = MapperContextMergeBehavior.ThrowException)
        {
            switch (mergeBehavior)
            {
            case MapperContextMergeBehavior.OverwriteDuplicates:
            {
                Lock.EnterWriteLock();

                try
                {
                    foreach (var row in mapperContext.MappingRows)
                    {
                        MappingRows[row.Key] = row.Value;
                    }
                }
                finally
                {
                    Lock.ExitWriteLock();
                }

                break;
            }

            case MapperContextMergeBehavior.SkipDuplicates:
            {
                Lock.EnterWriteLock();

                try
                {
                    foreach (var row in mapperContext.MappingRows)
                    {
                        if (!MappingRows.ContainsKey(row.Key))
                        {
                            MappingRows[row.Key] = row.Value;
                        }
                    }
                }
                finally
                {
                    Lock.ExitWriteLock();
                }

                break;
            }

            case MapperContextMergeBehavior.ThrowException:
            {
                Lock.EnterReadLock();

                try
                {
                    foreach (var row in mapperContext.MappingRows)
                    {
                        if (MappingRows.ContainsKey(row.Key))
                        {
                            throw new InvalidOperationException();
                        }
                    }
                }
                finally
                {
                    Lock.ExitReadLock();
                }

                break;
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(mergeBehavior), mergeBehavior, null);
            }
        }