每10秒对比文件哈希检测修改遇System.InvalidOperationException求助
嘿,这个错误我太熟了!咱们先搞清楚根源:当你正在遍历一个集合(比如用foreach循环跑监控文件列表)的时候,这个集合被修改了——不管是新增、删除元素,还是被重新赋值,CLR就会抛出System.InvalidOperationException: Collection was modified. Enumeration operation may not execute这个异常。结合你的场景,大概率是在10秒一次的哈希检查循环里,要么遍历的文件列表被其他代码偷偷改了,要么你在检查逻辑里不小心修改了这个列表本身。
下面给你几个实用的解决办法,挑适合你场景的来用:
先复制集合副本再枚举
每次检查哈希前,把要监控的文件列表复制到一个临时列表里,这样哪怕原集合被修改,也不会影响当前的检查流程。代码示例:// 假设你的原监控文件列表是 List<string> monitoredFiles var tempFileList = monitoredFiles.ToList(); // 创建副本,脱离原集合的引用 foreach (var filePath in tempFileList) { if (FileHasChanged(filePath)) { // 这里处理文件修改后的逻辑,哪怕修改原monitoredFiles也不会影响当前循环 } }改用线程安全的集合类型
如果你的监控列表会被多个线程操作(比如一个线程负责添加/移除监控文件,另一个线程跑哈希检查),直接用.NET自带的线程安全集合就好,比如ConcurrentDictionary<string, string>——它还能顺便存文件的历史哈希值,一举两得:// 初始化线程安全的哈希缓存,键是文件路径,值是历史哈希 private readonly ConcurrentDictionary<string, string> _fileHashStore = new ConcurrentDictionary<string, string>(); // 哈希检查逻辑 foreach (var fileEntry in _fileHashStore) { string filePath = fileEntry.Key; string oldHash = fileEntry.Value; string newHash = CalculateFileHash(filePath); // 替换成你计算哈希的方法 if (newHash != oldHash) { // 安全更新哈希值 _fileHashStore.TryUpdate(filePath, newHash, oldHash); // 这里处理文件被修改的事件 } }线程安全集合允许在枚举的同时修改集合,不会触发那个异常。
加锁保护集合的访问和修改
如果不想换集合类型,就在所有访问和修改集合的地方加锁,保证同一时间只有一个操作能碰这个集合:private List<string> _monitoredFiles = new List<string>(); private readonly object _collectionLock = new object(); // 哈希检查时加锁 lock (_collectionLock) { foreach (var filePath in _monitoredFiles) { if (FileHasChanged(filePath)) { // 处理逻辑 } } } // 任何修改集合的地方也要加锁,比如添加新监控文件 lock (_collectionLock) { _monitoredFiles.Add(@"C:\new_file_to_monitor.txt"); }
最后再提醒你:检查一下你的FileHasChanged()方法或者检查循环里的逻辑,有没有不小心修改了正在遍历的那个文件集合——比如发现文件被修改后就把它从列表里移除,或者临时添加新的监控项,这都会直接触发这个错误哦。
内容的提问来源于stack exchange,提问作者Steven M.

