/// <summary>
        /// Creates a new instance of <see cref="EventEnvelope"/> for the specified <paramref name="aggregateId"/>, <paramref name="version"/> and <paramref name="e"/>.
        /// </summary>
        /// <param name="correlationId"> The message correlation identifier that is assocaited with this <see cref="EventEnvelope"/>.</param>
        /// <param name="aggregateId">The unique <see cref="Aggregate"/> identifier that is the source of the associated <see cref="Event"/>.</param>
        /// <param name="version"> The aggregate version and associated event index that is the source of the associated <see cref="Event"/>.</param>
        /// <param name="e">The event payload that originated from the specified <see cref="Aggregate"/>.</param>
        public EventEnvelope(Guid correlationId, Guid aggregateId, EventVersion version, Event e)
        {
            Verify.NotNull(e, nameof(e));

            this.correlationId = correlationId;
            this.aggregateId = aggregateId;
            this.version = version;
            this.e = e;
        }
        /// <summary>
        /// Gets the set of <see cref="EventHandler"/> instances associated with the specified <paramref name="e"/>.
        /// </summary>
        /// <param name="e">The event for which to retrieve all <see cref="EventHandler"/> instances.</param>
        public IEnumerable<EventHandler> GetHandlersFor(Event e)
        {
            Verify.NotNull(e, nameof(e));

            EventHandler[] eventHandlers;
            Timeout timeout = e as Timeout;
            if (timeout != null && knownSagaTimeoutHandlers.TryGetValue(timeout.SagaType, out eventHandlers))
                return eventHandlers;

            return knownEventHandlers.TryGetValue(e.GetType(), out eventHandlers) ? eventHandlers : Enumerable.Empty<EventHandler>();
        }
        /// <summary>
        /// Apply the specified <see cref="Event"/> <paramref name="e"/> to the provided <paramref name="aggregate"/>.
        /// </summary>
        /// <param name="e">The event to be applied to the provided <paramref name="aggregate"/>.</param>
        /// <param name="aggregate">The <see cref="Aggregate"/> instance on which the event is to be applied.</param>
        public void Apply(Event e, Aggregate aggregate)
        {
            Verify.NotNull(e, nameof(e));
            Verify.NotNull(aggregate, nameof(aggregate));

            var applyMethods = GetKnownApplyMethods(aggregate);
            var applyMethod = GetApplyMethod(aggregate, e, applyMethods);

            Log.Trace("Applying event {0} to aggregate {1}", e, aggregate);

            applyMethod(aggregate, e);
        }
        /// <summary>
        /// Initializes a new instance of <see cref="EventContext"/> with the specified <paramref name="aggregateId"/> and <paramref name="headers"/>.
        /// </summary>
        /// <param name="aggregateId">The unique <see cref="Aggregate"/> identifier.</param>
        /// <param name="headers">The <see cref="Event"/> headers.</param>
        /// <param name="e">The <see cref="Event"/>.</param>
        public EventContext(Guid aggregateId, HeaderCollection headers, Event e)
        {
            Verify.NotEqual(Guid.Empty, aggregateId, nameof(aggregateId));
            Verify.NotNull(headers, nameof(headers));
            Verify.NotNull(e, nameof(e));

            this.originalContext = currentContext;
            this.thread = Thread.CurrentThread;
            this.aggregateId = aggregateId;
            this.headers = headers;
            this.@event = e;

            currentContext = this;
        }
        /// <summary>
        /// Raises the specified event.
        /// </summary>
        /// <param name="e">The <see cref="Event"/> to be raised.</param>
        protected void Raise(Event e)
        {
            Verify.NotNull(e, nameof(e));

            CommandContext.GetCurrent().Raise(e);
        }
        /// <summary>
        /// Add the specified <see cref="Event"/> <paramref name="e"/> to the current <see cref="CommandContext"/>.
        /// </summary>
        /// <param name="e">The <see cref="Event"/> to be raise.</param>
        internal void Raise(Event e)
        {
            Verify.NotNull(e, nameof(e));
            Verify.NotDisposed(this, disposed);

            raisedEvents.Add(e);
        }
        /// <summary>
        /// Get the associated apply method for the specified <see cref="Event"/> <paramref name="e"/> from the known <paramref name="applyMethods"/>.
        /// </summary>
        /// <param name="aggregate">The <see cref="Aggregate"/> instance on which the event is to be applied.</param>
        /// <param name="e">The <see cref="Event"/> to be applied.</param>
        /// <param name="applyMethods">The set of known apply methods for a given aggregate instance</param>
        private static Action<Aggregate, Event> GetApplyMethod(Aggregate aggregate, Event e, ApplyMethodCollection applyMethods)
        {
            Action<Aggregate, Event> applyMethod;
            Type eventType = e.GetType();

            if (applyMethods.TryGetValue(eventType, out applyMethod))
                return applyMethod;

            if (!applyMethods.ApplyOptional)
                throw new MappingException(Exceptions.AggregateApplyMethodNotFound.FormatWith(aggregate.GetType(), e.GetType()));

            return VoidApplyMethod;
        }