/// <summary>
        /// Private dispose method to release managed/unmanaged objects.
        /// If disposing = true clean up managed resources as well as unmanaged resources.
        /// If disposing = false only clean up unmanaged resources.
        /// </summary>
        /// <param name="disposing">Indicates whether or not to dispose managed resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (null != this.md5hash)
                {
                    this.md5hash.Dispose();
                    this.md5hash = null;
                }

                if (null != this.semaphore)
                {
                    this.semaphore.Dispose();
                    this.semaphore = null;
                }
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="MD5HashStream"/> class.
        /// </summary>
        /// <param name="stream">Stream object.</param>
        /// <param name="lastTransferOffset">Offset of the transferred bytes.</param>
        /// <param name="md5hashCheck">Whether need to calculate MD5Hash.</param>
        public MD5HashStream(
            Stream stream,
            long lastTransferOffset,
            bool md5hashCheck)
        {
            this.stream        = stream;
            this.md5hashOffset = lastTransferOffset;

            if ((0 == this.md5hashOffset) ||
                (!md5hashCheck))
            {
                this.finishedSeparateMd5Calculator  = true;
                this.succeededSeparateMd5Calculator = true;
            }
            else
            {
                this.semaphore = new SemaphoreSlim(1, 1);
            }

            if (md5hashCheck)
            {
                this.md5hash = new MD5Wrapper();
            }

            if ((!this.finishedSeparateMd5Calculator) &&
                (!this.stream.CanRead))
            {
                throw new NotSupportedException(string.Format(
                                                    CultureInfo.CurrentCulture,
                                                    Resources.StreamMustSupportReadException,
                                                    "Stream"));
            }

            if (!this.stream.CanSeek)
            {
                canSeek = false;

                if (!this.finishedSeparateMd5Calculator)
                {
                    throw new NotSupportedException(string.Format(
                                                        CultureInfo.CurrentCulture,
                                                        Resources.StreamMustSupportSeekException,
                                                        "Stream"));
                }
            }
        }