protected void RaiseEvents(Queue deQueue)
        {
            if ((deQueue != null) && (deQueue.Count > 0))
            {
                DelayedEvent de = null;
                while (deQueue.Count > 0)
                {
                    de = deQueue.Dequeue() as DelayedEvent;
                    switch (de.Args.ChangeType)
                    {
                    case WatcherChangeTypes.Changed:
                        this.OnChanged(de.Args);
                        break;

                    case WatcherChangeTypes.Created:
                        this.OnCreated(de.Args);
                        break;

                    case WatcherChangeTypes.Deleted:
                        this.OnDeleted(de.Args);
                        break;

                    case WatcherChangeTypes.Renamed:
                        this.OnRenamed(de.Args as RenamedEventArgs);
                        break;
                    }
                }
            }
        }
        public virtual bool IsDuplicate(object obj)
        {
            DelayedEvent delayedEvent = obj as DelayedEvent;

            if (delayedEvent == null)
            {
                return(false); // this is not null so they are different
            }
            else
            {
                FileSystemEventArgs eO1  = this._args;
                RenamedEventArgs    reO1 = this._args as RenamedEventArgs;
                FileSystemEventArgs eO2  = delayedEvent._args;
                RenamedEventArgs    reO2 = delayedEvent._args as RenamedEventArgs;
                // The events are equal only if they are of the same type (reO1 and reO2
                // are both null or NOT NULL) and have all properties equal.
                // We also eliminate Changed events that follow recent Created events
                // because many apps create new files by creating an empty file and then
                // they update the file with the file content.
                return(((eO1 != null && eO2 != null && eO1.ChangeType == eO2.ChangeType &&
                         eO1.FullPath == eO2.FullPath && eO1.Name == eO2.Name) &&
                        ((reO1 == null & reO2 == null) || (reO1 != null && reO2 != null &&
                                                           reO1.OldFullPath == reO2.OldFullPath && reO1.OldName == reO2.OldName))) ||
                       (eO1 != null && eO2 != null && eO1.ChangeType == WatcherChangeTypes.Created &&
                        eO2.ChangeType == WatcherChangeTypes.Changed &&
                        eO1.FullPath == eO2.FullPath && eO1.Name == eO2.Name));
            }
        }
        private void ElapsedEventHandler(Object sender, ElapsedEventArgs e)
        {
            // We don't fire the events inside the lock. We will queue them here until
            // the code exits the locks.
            Queue eventsToBeFired = null;

            if (Monitor.TryEnter(this._enterThread))
            {
                // Only one thread at a time is processing the events
                try
                {
                    eventsToBeFired = new Queue(32);
                    // Lock the collection while processing the events
                    lock (this._events.SyncRoot)
                    {
                        DelayedEvent current = null;
                        for (int i = 0; i < this._events.Count; i++)
                        {
                            current = this._events[i] as DelayedEvent;
                            if (current.Delayed)
                            {
                                // This event has been delayed already so we can fire it
                                // We just need to remove any duplicates
                                for (int j = i + 1; j < this._events.Count; j++)
                                {
                                    if (current.IsDuplicate(this._events[j]))
                                    {
                                        // Removing later duplicates
                                        this._events.RemoveAt(j);
                                        j--; // Don't skip next event
                                    }
                                }
                                // Add the event to the list of events to be fired
                                eventsToBeFired.Enqueue(current);
                                // Remove it from the current list
                                this._events.RemoveAt(i);
                                i--; // Don't skip next event
                            }
                            else
                            {
                                // This event was not delayed yet, so we will delay processing
                                // this event for at least one timer interval
                                current.Delayed = true;
                            }
                        }
                    }
                }
                finally
                {
                    Monitor.Exit(this._enterThread);
                }
            }
            // else - this timer event was skipped, processing will happen during the next timer event

            // Now fire all the events if any events are in eventsToBeFired
            this.RaiseEvents(eventsToBeFired);
        }