C# FileSystemWatcher在一段时间后不会启动

C# FileSystemWatcher在一段时间后不会启动,c#,.net,c#-4.0,filesystemwatcher,C#,.net,C# 4.0,Filesystemwatcher,我有下面的代码,我用它来监视一个目录中的文本文件,这个目录一天会收到两次新文件,这个代码可以正常工作一段时间,但在那之后,它会停止触发一个创建的事件 [PermissionSet(SecurityAction.Demand, Name="FullTrust")] public static void Run() { FileSystemWatcher watcher = new FileSystemWatcher(); watcher.Path = @"c:\users\docu

我有下面的代码,我用它来监视一个目录中的文本文件,这个目录一天会收到两次新文件,这个代码可以正常工作一段时间,但在那之后,它会停止触发一个创建的事件

[PermissionSet(SecurityAction.Demand, Name="FullTrust")]
public static void Run()
{
    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = @"c:\users\documents\";

    watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
       | NotifyFilters.FileName | NotifyFilters.DirectoryName;

    watcher.Filter = "*.txt";

    // Add event handlers.
    watcher.Created += new FileSystemEventHandler(OnCreated);

    // Begin watching.
    watcher.EnableRaisingEvents = true;

    // Wait for the user to quit the program.
    Console.WriteLine("Press \'q\' to quit the sample.");
    while(Console.Read()!='q');
}

private static void OnCreated(object source, FileSystemEventArgs e)
{
   Console.WriteLine("File: " +  e.FullPath + " " + e.ChangeType);
}
我想不出这个问题


另外,我想知道一个简单的替代方法(如果有的话),因为我觉得这个方法不可靠。

因为在
运行
方法完成后,
观察者
有资格进行垃圾收集。 这意味着在一段时间后,
watcher
将被收集,显然将停止引发事件

要解决此问题,请在外部范围内保留观察者的参考:

private static FileSystemWatcher watcher;

public static void Run()
{
    watcher = new FileSystemWatcher();
    ...
}

这方面的问题是,对FILESYSTEMWATCHER的引用是由GC收集的,因此过了一段时间后,FILEWATCHER有一个空引用,导致没有引发事件

解决方案:-

private static FileSystemWatcher watcher;
public static void Run()
{
watcher = new FileSystemWatcher();
...
GC.KeepAlive(watcher);  
}

仅仅按照建议在外部范围内保留观察者的引用并不能解决问题。我已明确指定GC不应收集FileWatcher对象。

假设您的watcher没有超出范围,您可以检查发生的任何错误,例如耗尽watchers内部缓冲区。。。 watcher.Error+=watcher\u错误; ... 私有无效观察程序\u错误(对象发送方,ErrorEventArgs e) { WriteLine(“Watcher_错误:+e.GetException().Message”); }

不确定给出的原因是否正确。Run方法在有人按下字母“q”之前不会退出,因此局部变量仍然有效且不符合GC的条件。我错了吗?@Steve:引用的生命周期不一定是通过变量的作用域来延长的,只取决于引用是否处于“活动”状态。由于在
watcher.EnableRaisingEvents=true之后不再使用
watcher
局部变量 GC可能认为它不活动,可能会收集它。@ MichaelBurr,你能给我一些参考(没有双关打算)吗?因为,在我看来,局部变量观察者(直到从run方法退出)仍然引用堆中的有效对象,并且当仍然有对该对象的引用处于活动状态时,GC不应销毁该对象。@Steve:我很难找到一个好的引用。我认为有几篇文章讨论了只有局部变量引用的计时器是如何不会启动的,因为它们比预期的要早。我还认为MS至少更改了一个timer类,以在私有静态列表中维护对启用计时器的引用,直到它们触发以修复该问题为止(尽管我找不到有关该问题的详细信息,所以我可能记错了)。@Steve:但是,如果您阅读
System.timers.timer
类MSDN文档上的备注,您将看到:“代码包含类级别和Main内部的计时器变量声明。要了解主动垃圾收集如何影响在长时间运行的方法中声明的计时器,可以注释掉类级声明并取消对局部变量的注释。要防止计时器被收集,请取消对“Main”结尾处的GC.KeepAlive方法的注释,这意味着可以在作用域结束之前对
aTimer
进行GC。请注意,
FileSystemWatcher
有一点不可靠的名声(尽管我不确定这是否是
FileSystemWatcher
实现的问题,或者它的使用方式有问题)。有关其他人如何处理该问题的建议,请参阅。另外,我的理解是,
FileSystemWatcher
使用系统的
ReadDirectoryChangesW
API。阅读Jim Beverridge的这篇文章,了解该API的详细信息可能会有所帮助: