From 8548814c5e5db2e1ae30d202f6810722e2ff0ac8 Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Wed, 23 Sep 2026 14:29:27 +0200 Subject: [PATCH] FileSystemWatcher in C#: retarget net10.0, drop the broken dispose pattern, IOException TextFileManager.Dispose() called GC.SuppressFinalize(true), which boxes a bool and suppresses nothing, and Dispose(bool) was public, so any caller could mark the instance disposed without disposing the watcher. The class owns one managed resource, so the finalizer and the Dispose(bool) overload are removed and Dispose() disposes the FileSystemWatcher directly. Also: - both projects retargeted from net6.0 to net10.0 - Create() throws IOException instead of the base Exception type - misspelled field FileUtil._dircetoryToMonitor renamed to _directoryToMonitor (TextFileManager._desposed went away with the dispose pattern) - Program.cs notes above the four file operations that the output order is not guaranteed, because the watcher raises its events on another thread - Microsoft.NET.Test.Sdk 18.10.1, xunit 2.9.3, xunit.runner.visualstudio 4.0.0, coverlet.collector 10.0.1 Build is clean and tests run 4 of 4 on SDK 10.0.302. --- .../ExampleApp/ExampleApp.csproj | 2 +- .../ExampleApp/FileUtil.cs | 10 +++---- .../ExampleApp/Program.cs | 1 + .../ExampleApp/TextFileManager.cs | 27 ++----------------- .../Tests/Tests.csproj | 10 +++---- 5 files changed, 14 insertions(+), 36 deletions(-) diff --git a/files-csharp/FileSystemWatcherExample/ExampleApp/ExampleApp.csproj b/files-csharp/FileSystemWatcherExample/ExampleApp/ExampleApp.csproj index 40c60dd4c8..7f1dc2eb2f 100644 --- a/files-csharp/FileSystemWatcherExample/ExampleApp/ExampleApp.csproj +++ b/files-csharp/FileSystemWatcherExample/ExampleApp/ExampleApp.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net10.0 enable enable diff --git a/files-csharp/FileSystemWatcherExample/ExampleApp/FileUtil.cs b/files-csharp/FileSystemWatcherExample/ExampleApp/FileUtil.cs index ea01fb70dc..38dc2507f5 100644 --- a/files-csharp/FileSystemWatcherExample/ExampleApp/FileUtil.cs +++ b/files-csharp/FileSystemWatcherExample/ExampleApp/FileUtil.cs @@ -1,18 +1,18 @@ public static class FileUtil { - private static string? _dircetoryToMonitor; + private static string? _directoryToMonitor; public static string DirectoryToMonitor { get { - if(string.IsNullOrEmpty(_dircetoryToMonitor)) + if(string.IsNullOrEmpty(_directoryToMonitor)) { - _dircetoryToMonitor = Path.Combine(Directory.GetCurrentDirectory(),"bin","DirectoryToMonitor"); - Directory.CreateDirectory(_dircetoryToMonitor); + _directoryToMonitor = Path.Combine(Directory.GetCurrentDirectory(),"bin","DirectoryToMonitor"); + Directory.CreateDirectory(_directoryToMonitor); } - return _dircetoryToMonitor; + return _directoryToMonitor; } } } \ No newline at end of file diff --git a/files-csharp/FileSystemWatcherExample/ExampleApp/Program.cs b/files-csharp/FileSystemWatcherExample/ExampleApp/Program.cs index c27b2cb138..c34e7b5c5f 100644 --- a/files-csharp/FileSystemWatcherExample/ExampleApp/Program.cs +++ b/files-csharp/FileSystemWatcherExample/ExampleApp/Program.cs @@ -7,6 +7,7 @@ var updatedContents = new string[] { "Hello World" }; using var manager = new TextFileManager(FileUtil.DirectoryToMonitor); +// The watcher raises its events on another thread, so the order of the output below is not guaranteed. manager.Create(fileName, contents); manager.Update(fileName, updatedContents); manager.Rename(fileName, updatedFileName); diff --git a/files-csharp/FileSystemWatcherExample/ExampleApp/TextFileManager.cs b/files-csharp/FileSystemWatcherExample/ExampleApp/TextFileManager.cs index 7782f0b80a..d6c8217676 100644 --- a/files-csharp/FileSystemWatcherExample/ExampleApp/TextFileManager.cs +++ b/files-csharp/FileSystemWatcherExample/ExampleApp/TextFileManager.cs @@ -1,6 +1,5 @@ public class TextFileManager : IDisposable { - private bool _desposed; private readonly string _rootDirectory; private readonly FileSystemWatcher _fileSystemWatcher; @@ -17,7 +16,7 @@ public void Create(string fileName, IEnumerable content) { var path = AbsolutePath(fileName); if (File.Exists(path)) - throw new Exception($"File With the same name exists: {fileName}"); + throw new IOException($"File With the same name exists: {fileName}"); File.WriteAllLines(path, content); } @@ -102,27 +101,5 @@ private void HandleCreated(object sender, FileSystemEventArgs e) private string AbsolutePath(string fileName) => Path.Combine(_rootDirectory, fileName); - ~TextFileManager() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(true); - } - - public virtual void Dispose(bool disposing) - { - if(_desposed) - return; - - if(disposing) - { - _fileSystemWatcher.Dispose(); - } - - _desposed = true; - } + public void Dispose() => _fileSystemWatcher.Dispose(); } \ No newline at end of file diff --git a/files-csharp/FileSystemWatcherExample/Tests/Tests.csproj b/files-csharp/FileSystemWatcherExample/Tests/Tests.csproj index 5383969f54..3093d5fe69 100644 --- a/files-csharp/FileSystemWatcherExample/Tests/Tests.csproj +++ b/files-csharp/FileSystemWatcherExample/Tests/Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 enable enable @@ -9,13 +9,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all