HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

FileSystemWatcher firing multiple events

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
firingeventsmultiplefilesystemwatcher

Problem

Like others (FileSystemWatcher Changed event is raised twice) I am facing the problem that events of filesystemwatcher are raised twice. I require to catch all non-duplicate events of watcher in real time. I came up with this. So, I want to know if it will be efficient/over-kill/buggy to use this class.

```
class ModifiedFileSystemWatcher:FileSystemWatcher
{
public new event RenamedEventHandler Renamed;
public new event FileSystemEventHandler Deleted;
public new event FileSystemEventHandler Created;
public new event FileSystemEventHandler Changed;

class BooleanWrapper{
public bool value { get; set; }
}

//stores refrences of previously fired events with same file source
Dictionary raiseEvent = new Dictionary();

public int WaitingTime { get; set; } //waiting time, any new event raised with same file source will discard previous one

public ModifiedFileSystemWatcher(string filename="", string filter="."):base(filename,filter)
{
base.Changed += ModifiedFileSystemWatcher_Changed;
base.Created += ModifiedFileSystemWatcher_Created;
base.Deleted += ModifiedFileSystemWatcher_Deleted;
base.Renamed += ModifiedFileSystemWatcher_Renamed;
WaitingTime = 100;
}

void PreventDuplicate(FileSystemEventHandler _event, FileSystemEventArgs e)
{
if (_event != null)
{
//create a reference
BooleanWrapper w = new BooleanWrapper() { value = true }; //this event will be fired

BooleanWrapper t; //tmp
if (raiseEvent.TryGetValue(e.FullPath, out t))
{
//a previous event occurred which is waiting [delayed by WaitingTime]
t.value = false; //set its reference to false; that event will be skipped
t = w;//store current reference in dictionary
}
else raiseEvent[e.FullPath] = w; //no previous event, store our reference

//Wait on a se

Solution

I copied your code into a new console application. Your constructor is "eating" the base default constructor, and now I can't pass a path parameter, I have to trust that filename will work if I give it a folder path. Let's see..

public ModifiedFileSystemWatcher(string filename="", string filter="*.*"):base(filename,filter)
{
    /* constructor */
}


This would be easier to read on two lines:

public ModifiedFileSystemWatcher(string filename="", string filter="*.*")
    : base(filename,filter)
{
    /* constructor */
}


Changing the names of constructor arguments is confusing. In this case you're passing filename as the base constructor's path parameter, but filter is passed as filter. I would rename filename to path to avoid confusion.

The optional parameters are surprising, too - a FileSystemWatcher exposes a parameterless constructor, one with only a path, and one with both a path and a filter. Your optional parameters add a constructor for a filter without a path.

This is a rather unusual way of assigning a value in a dictionary:

BooleanWrapper w = new BooleanWrapper() { value = true };
BooleanWrapper t;
if (raiseEvent.TryGetValue(e.FullPath, out t))
{
    t.value = false;
    t = w; //store current reference in dictionary
}


This might work, but I find raiseEvent[e.FullPath] = w; makes the intent much more explicit.

Code Snippets

public ModifiedFileSystemWatcher(string filename="", string filter="*.*"):base(filename,filter)
{
    /* constructor */
}
public ModifiedFileSystemWatcher(string filename="", string filter="*.*")
    : base(filename,filter)
{
    /* constructor */
}
BooleanWrapper w = new BooleanWrapper() { value = true };
BooleanWrapper t;
if (raiseEvent.TryGetValue(e.FullPath, out t))
{
    t.value = false;
    t = w; //store current reference in dictionary
}

Context

StackExchange Code Review Q#48930, answer score: 3

Revisions (0)

No revisions yet.