/// <summary>
        /// Locks inner lock for <paramref name="key"/> for exclusive access.
        /// </summary>
        /// <param name="key">Key to distinguish different locks/processes.</param>
        /// <returns>Object which is used to exit lock when disposed.</returns>
        public IDisposable Lock(object key)
        {
            Ensure.NotNull(key, "key");

            if (keyMapper != null)
            {
                key = keyMapper(key);
            }

            LockProvider provider;

            using (storageLock.Lock())
            {
                if (!storage.TryGetValue(key, out provider))
                {
                    provider           = new LockProvider();
                    provider.Disposed += OnProviderDisposed;
                    storage[key]       = provider;
                }
            }

            return(provider.Lock());
        }