Im trying write program in c# which is watching multiple folders. If in any of watched folders are added file, program should create copy in defined paths. My problem is when i create file, program create copies in wrong folder
e.g. if i add file into
C:\folder1\stuff\it should create copy in
D:\stuff1\copied1...3\but instead it created copies in
D:\stuff2\copied1...3\
There is code :
namespace Watcher { public class Watcher { struct Paths { public string sourcePath; public List<string> destinations; public FileSystemWatcher Watcher; } List<Paths> paths = new List<Paths>(); public Watcher() { createWatchTower(); } public void watch() { foreach (Paths p in paths) { p.Watcher.Created += (sender, e) => onCreate(sender, e, p.destinations); } } void createWatchTower() { Paths p1; p1.destinations = new List<string>(); p1.sourcePath = @"C:\folder1\stuff\"; p1.Watcher = new FileSystemWatcher(); p1.Watcher.Path = p1.sourcePath; p1.Watcher.EnableRaisingEvents = true; p1.destinations.Add(@"D:\stuff1\copied1\"); p1.destinations.Add(@"D:\stuff1\copied2\"); p1.destinations.Add(@"D:\stuff1\copied3\"); paths.Add(p1); Paths p2; p2.destinations = new List<string>(); p2.sourcePath = @"C:\folder2\stuff2"; p2.Watcher = new FileSystemWatcher(); p2.Watcher.Path = p2.sourcePath; p2.Watcher.EnableRaisingEvents = true; p2.destinations.Add(@"D:\stuff2\copied1\"); p2.destinations.Add(@"D:\stuff2\copied2\"); p2.destinations.Add(@"D:\stuff2\copied3\"); paths.Add(p2); } private void onCreate(object o, FileSystemEventArgs e, List<string> dest) { foreach (string s in dest) { try { System.IO.File.Copy(e.FullPath, s + e.Name, true); } catch (Exception ex) { Console.WriteLine(ex); } } } } }
Could anyone help me ? I think its because event in foreach, but i cant find sollution for this. Thanks much post
If you are not using C# 5 then the problem is the closure on p
in the foreach-loop in the watch
method:
foreach (Paths p in paths)
{
p.Watcher.Created += (sender, e) => onCreate(sender, e, p.destinations);
}
When using p
inside the lambda it will capture the variable, not its value. So if the Created
event is raised p
will refer to the last item of the paths
list.
You can avoid that by introducing a temporary variable inside the foreach-loop:
foreach (Paths p in paths)
{
var tmp = p;
p.Watcher.Created += (sender, e) => onCreate(sender, e, tmp.destinations);
}
You can find a more detailed analysis of what changed in C# 5 in this Stackoverflow question.