// See the LICENSE file in the project root for more information.
#nullable enable
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace System.IO
/// away from paths during normalization, but if we see such a path at this point it should be
/// normalized and has retained the final characters. (Typically from one of the *Info classes)
/// </summary>
- /// TODO: add atribute [return: NotNullIfNotNull("path")]
+ [return: NotNullIfNotNull("path")]
internal static string? EnsureExtendedPrefixIfNeeded(string? path)
{
if (path != null && (path.Length >= MaxShortPath || EndsWithPeriodOrSpace(path)))
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
using System.Buffers;
namespace System.Text
/// </summary>
internal ref struct ValueUtf8Converter
{
- private byte[] _arrayToReturnToPool;
+ private byte[]? _arrayToReturnToPool;
private Span<byte> _bytes;
public ValueUtf8Converter(Span<byte> initialBuffer)
public void Dispose()
{
- byte[] toReturn = _arrayToReturnToPool;
+ byte[]? toReturn = _arrayToReturnToPool;
if (toReturn != null)
{
_arrayToReturnToPool = null;
public delegate void ErrorEventHandler(object sender, System.IO.ErrorEventArgs e);
public partial class FileSystemEventArgs : System.EventArgs
{
- public FileSystemEventArgs(System.IO.WatcherChangeTypes changeType, string directory, string name) { }
+ public FileSystemEventArgs(System.IO.WatcherChangeTypes changeType, string directory, string? name) { }
public System.IO.WatcherChangeTypes ChangeType { get { throw null; } }
public string FullPath { get { throw null; } }
- public string Name { get { throw null; } }
+ public string? Name { get { throw null; } }
}
public delegate void FileSystemEventHandler(object sender, System.IO.FileSystemEventArgs e);
public partial class FileSystemWatcher : System.ComponentModel.Component, System.ComponentModel.ISupportInitialize
public int InternalBufferSize { get { throw null; } set { } }
public System.IO.NotifyFilters NotifyFilter { get { throw null; } set { } }
public string Path { get { throw null; } set { } }
- public override System.ComponentModel.ISite Site { get { throw null; } set { } }
- public System.ComponentModel.ISynchronizeInvoke SynchronizingObject { get { throw null; } set { } }
- public event System.IO.FileSystemEventHandler Changed { add { } remove { } }
- public event System.IO.FileSystemEventHandler Created { add { } remove { } }
- public event System.IO.FileSystemEventHandler Deleted { add { } remove { } }
- public event System.IO.ErrorEventHandler Error { add { } remove { } }
- public event System.IO.RenamedEventHandler Renamed { add { } remove { } }
+ public override System.ComponentModel.ISite? Site { get { throw null; } set { } }
+ public System.ComponentModel.ISynchronizeInvoke? SynchronizingObject { get { throw null; } set { } }
+ public event System.IO.FileSystemEventHandler? Changed { add { } remove { } }
+ public event System.IO.FileSystemEventHandler? Created { add { } remove { } }
+ public event System.IO.FileSystemEventHandler? Deleted { add { } remove { } }
+ public event System.IO.ErrorEventHandler? Error { add { } remove { } }
+ public event System.IO.RenamedEventHandler? Renamed { add { } remove { } }
public void BeginInit() { }
protected override void Dispose(bool disposing) { }
public void EndInit() { }
{
public InternalBufferOverflowException() { }
protected InternalBufferOverflowException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
- public InternalBufferOverflowException(string message) { }
- public InternalBufferOverflowException(string message, System.Exception inner) { }
+ public InternalBufferOverflowException(string? message) { }
+ public InternalBufferOverflowException(string? message, System.Exception? inner) { }
}
[System.FlagsAttribute]
public enum NotifyFilters
}
public partial class RenamedEventArgs : System.IO.FileSystemEventArgs
{
- public RenamedEventArgs(System.IO.WatcherChangeTypes changeType, string directory, string name, string oldName) : base (default(System.IO.WatcherChangeTypes), default(string), default(string)) { }
+ public RenamedEventArgs(System.IO.WatcherChangeTypes changeType, string directory, string? name, string? oldName) : base (default(System.IO.WatcherChangeTypes), default(string), default(string)) { }
public string OldFullPath { get { throw null; } }
- public string OldName { get { throw null; } }
+ public string? OldName { get { throw null; } }
}
public delegate void RenamedEventHandler(object sender, System.IO.RenamedEventArgs e);
public partial struct WaitForChangedResult
private object _dummy;
private int _dummyPrimitive;
public System.IO.WatcherChangeTypes ChangeType { readonly get { throw null; } set { } }
- public string Name { readonly get { throw null; } set { } }
- public string OldName { readonly get { throw null; } set { } }
+ public string? Name { readonly get { throw null; } set { } }
+ public string? OldName { readonly get { throw null; } set { } }
public bool TimedOut { readonly get { throw null; } set { } }
}
[System.FlagsAttribute]
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
+ <Nullable>enable</Nullable>
<Configurations>netcoreapp-Debug;netcoreapp-Release</Configurations>
</PropertyGroup>
<ItemGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <Nullable>enable</Nullable>
<Configurations>netcoreapp-FreeBSD-Debug;netcoreapp-FreeBSD-Release;netcoreapp-Linux-Debug;netcoreapp-Linux-Release;netcoreapp-OSX-Debug;netcoreapp-OSX-Release;netcoreapp-Windows_NT-Debug;netcoreapp-Windows_NT-Release</Configurations>
</PropertyGroup>
<ItemGroup>
public class FileSystemEventArgs : EventArgs
{
private readonly WatcherChangeTypes _changeType;
- private readonly string _name;
+ private readonly string? _name;
private readonly string _fullPath;
/// <devdoc>
/// Initializes a new instance of the <see cref='System.IO.FileSystemEventArgs'/> class.
/// </devdoc>
- public FileSystemEventArgs(WatcherChangeTypes changeType, string directory, string name)
+ public FileSystemEventArgs(WatcherChangeTypes changeType, string directory, string? name)
{
_changeType = changeType;
_name = name;
/// This is like Path.Combine, except without argument validation,
/// and a separator is used even if the name argument is empty.
/// </remarks>
- internal static string Combine(string directoryPath, string name)
+ internal static string Combine(string directoryPath, string? name)
{
bool hasSeparator = false;
if (directoryPath.Length > 0)
/// <devdoc>
/// Gets the name of the affected file or directory.
/// </devdoc>
- public string Name
+ public string? Name
{
get
{
switch (error.Error)
{
case Interop.Error.EMFILE:
- string maxValue = ReadMaxUserLimit(MaxUserInstancesPath);
+ string? maxValue = ReadMaxUserLimit(MaxUserInstancesPath);
string message = !string.IsNullOrEmpty(maxValue) ?
SR.Format(SR.IOException_INotifyInstanceUserLimitExceeded_Value, maxValue) :
SR.IOException_INotifyInstanceUserLimitExceeded;
/// Cancellation for the currently running watch operation.
/// This is non-null if an operation has been started and null if stopped.
/// </summary>
- private CancellationTokenSource _cancellation;
+ private CancellationTokenSource? _cancellation;
/// <summary>Reads the value of a max user limit path from procfs.</summary>
/// <param name="path">The path to read.</param>
/// <returns>The value read, or "0" if a failure occurred.</returns>
- private static string ReadMaxUserLimit(string path)
+ private static string? ReadMaxUserLimit(string path)
{
try { return File.ReadAllText(path).Trim(); }
catch { return null; }
internal void Start()
{
// Schedule a task to read from the inotify queue and process the events.
- Task.Factory.StartNew(obj => ((RunningInstance)obj).ProcessEvents(),
+ Task.Factory.StartNew(obj => ((RunningInstance)obj!).ProcessEvents(),
this, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
// PERF: As needed, we can look into making this use async I/O rather than burning
/// <summary>Adds a watch on a directory to the existing inotify handle.</summary>
/// <param name="parent">The parent directory entry.</param>
/// <param name="directoryName">The new directory path to monitor, relative to the root.</param>
- private void AddDirectoryWatchUnlocked(WatchedDirectory parent, string directoryName)
+ private void AddDirectoryWatchUnlocked(WatchedDirectory? parent, string directoryName)
{
string fullPath = parent != null ? parent.GetPath(false, directoryName) : directoryName;
Exception exc;
if (error.Error == Interop.Error.ENOSPC)
{
- string maxValue = ReadMaxUserLimit(MaxUserWatchesPath);
+ string? maxValue = ReadMaxUserLimit(MaxUserWatchesPath);
string message = !string.IsNullOrEmpty(maxValue) ?
SR.Format(SR.IOException_INotifyWatchesUserLimitExceeded_Value, maxValue) :
SR.IOException_INotifyWatchesUserLimitExceeded;
exc = Interop.GetExceptionForIoErrno(error, fullPath);
}
- FileSystemWatcher watcher;
- if (_weakWatcher.TryGetTarget(out watcher))
+ if (_weakWatcher.TryGetTarget(out FileSystemWatcher? watcher))
{
watcher.OnError(new ErrorEventArgs(exc));
}
}
// Then store the path information into our map.
- WatchedDirectory directoryEntry;
+ WatchedDirectory? directoryEntry;
bool isNewDirectory = false;
if (_wdToPathMap.TryGetValue(wd, out directoryEntry))
{
// of the world, but there's little that can be done about that.)
if (directoryEntry.Parent != parent)
{
- if (directoryEntry.Parent != null)
- {
- directoryEntry.Parent.Children.Remove (directoryEntry);
- }
+ directoryEntry.Parent?.Children!.Remove (directoryEntry);
directoryEntry.Parent = parent;
if (parent != null)
{
Debug.Assert (_includeSubdirectories);
lock (SyncObj)
{
- if (directoryEntry.Parent != null)
- {
- directoryEntry.Parent.Children.Remove (directoryEntry);
- }
+ directoryEntry.Parent?.Children!.Remove(directoryEntry);
RemoveWatchedDirectoryUnlocked (directoryEntry, removeInotify);
}
}
// When cancellation is requested, clear out all watches. This should force any active or future reads
// on the inotify handle to return 0 bytes read immediately, allowing us to wake up from the blocking call
// and exit the processing loop and clean up.
- var ctr = _cancellationToken.UnsafeRegister(obj => ((RunningInstance)obj).CancellationCallback(), this);
+ var ctr = _cancellationToken.UnsafeRegister(obj => ((RunningInstance)obj!).CancellationCallback(), this);
try
{
// Previous event information
ReadOnlySpan<char> previousEventName = ReadOnlySpan<char>.Empty;
- WatchedDirectory previousEventParent = null;
+ WatchedDirectory? previousEventParent = null;
uint previousEventCookie = 0;
// Process events as long as we're not canceled and there are more to read...
// so as to avoid a rooted cycle that would prevent our processing loop from ever ending
// if the watcher is dropped by the user without being disposed. If we can't get the watcher,
// there's nothing more to do (we can't raise events), so bail.
- FileSystemWatcher watcher;
+ FileSystemWatcher? watcher;
if (!_weakWatcher.TryGetTarget(out watcher))
{
break;
uint mask = nextEvent.mask;
ReadOnlySpan<char> expandedName = ReadOnlySpan<char>.Empty;
- WatchedDirectory associatedDirectoryEntry = null;
+ WatchedDirectory? associatedDirectoryEntry = null;
// An overflow event means that we can't trust our state without restarting since we missed events and
// some of those events could be a directory create, meaning we wouldn't have added the directory to the
}
catch (Exception exc)
{
- FileSystemWatcher watcher;
- if (_weakWatcher.TryGetTarget(out watcher))
+ if (_weakWatcher.TryGetTarget(out FileSystemWatcher? watcher))
{
watcher.OnError(new ErrorEventArgs(exc));
}
{
/// <summary>A StringBuilder cached on the current thread to avoid allocations when possible.</summary>
[ThreadStatic]
- private static StringBuilder t_builder;
+ private static StringBuilder? t_builder;
/// <summary>The parent directory.</summary>
- internal WatchedDirectory Parent;
+ internal WatchedDirectory? Parent;
/// <summary>The watch descriptor associated with this directory.</summary>
internal int WatchDescriptor;
/// <summary>The filename of this directory.</summary>
- internal string Name;
+ internal string? Name;
/// <summary>Child directories of this directory for which we added explicit watches.</summary>
- internal List<WatchedDirectory> Children;
+ internal List<WatchedDirectory>? Children;
/// <summary>Child directories of this directory for which we added explicit watches. This is the same as Children, but ensured to be initialized as non-null.</summary>
- internal List<WatchedDirectory> InitializedChildren
- {
- get
- {
- if (Children == null)
- {
- Children = new List<WatchedDirectory> ();
- }
- return Children;
- }
- }
+ internal List<WatchedDirectory> InitializedChildren => Children ??= new List<WatchedDirectory>();
// PERF: Work is being done here proportionate to depth of watch directories.
// If this becomes a bottleneck, we'll need to come up with another mechanism
/// <param name="relativeToRoot">Whether to get a path relative to the root directory being watched, or a full path.</param>
/// <param name="additionalName">An additional name to include in the path, relative to this directory.</param>
/// <returns>The computed path.</returns>
- internal string GetPath(bool relativeToRoot, string additionalName = null)
+ internal string GetPath(bool relativeToRoot, string? additionalName = null)
{
// Use our cached builder
- StringBuilder builder = t_builder;
- if (builder == null)
- {
- t_builder = builder = new StringBuilder();
- }
+ StringBuilder builder = (t_builder ??= new StringBuilder());
builder.Clear();
// Write the directory's path. Then if an additional filename was supplied, append it
// See the LICENSE file in the project root for more information.
using System.Buffers;
-using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
if (IsSuspended())
return;
- CancellationTokenSource token = _cancellation;
+ CancellationTokenSource? token = _cancellation;
if (token != null)
{
_cancellation = null;
// ---- PAL layer ends here ----
// -----------------------------
- private CancellationTokenSource _cancellation;
+ private CancellationTokenSource? _cancellation;
private static FSEventStreamEventFlags TranslateFlags(NotifyFilters flagsToTranslate)
{
private FSEventStreamEventFlags _filterFlags;
// The EventStream to listen for events on
- private SafeEventStreamHandle _eventStream;
+ private SafeEventStreamHandle? _eventStream;
// Callback delegate for the EventStream events
- private Interop.EventStream.FSEventStreamCallback _callback;
+ private Interop.EventStream.FSEventStreamCallback? _callback;
// Token to monitor for cancellation requests, upon which processing is stopped and all
// state is cleaned up.
// Calling RunLoopStop multiple times SegFaults so protect the call to it
private bool _stopping;
- private ExecutionContext _context;
+ private ExecutionContext? _context;
internal RunningInstance(
FileSystemWatcher watcher,
_includeChildren = includeChildren;
_filterFlags = filter;
_cancellationToken = cancelToken;
- _cancellationToken.UnsafeRegister(obj => ((RunningInstance)obj).CancellationCallback(), this);
+ _cancellationToken.UnsafeRegister(obj => ((RunningInstance)obj!).CancellationCallback(), this);
_stopping = false;
}
Debug.Assert(s_scheduledStreamsCount == 0);
s_scheduledStreamsCount = 1;
var runLoopStarted = new ManualResetEventSlim();
- new Thread(WatchForFileSystemEventsThreadStart) { IsBackground = true }.Start(new object[] { runLoopStarted, eventStream });
+ new Thread(args =>
+ {
+ object[] inputArgs = (object[])args!;
+ WatchForFileSystemEventsThreadStart((ManualResetEventSlim)inputArgs[0], (SafeEventStreamHandle)inputArgs[1]);
+ })
+ { IsBackground = true }.Start(new object[] { runLoopStarted, eventStream });
+
runLoopStarted.Wait();
}
}
}
}
- private static void WatchForFileSystemEventsThreadStart(object args)
+ private static void WatchForFileSystemEventsThreadStart(ManualResetEventSlim runLoopStarted, SafeEventStreamHandle eventStream)
{
- var inputArgs = (object[])args;
- var runLoopStarted = (ManualResetEventSlim)inputArgs[0];
- var _eventStream = (SafeEventStreamHandle)inputArgs[1];
// Get this thread's RunLoop
IntPtr runLoop = Interop.RunLoop.CFRunLoopGetCurrent();
s_watcherRunLoop = runLoop;
Debug.Assert(retainResult == runLoop, "CFRetain is supposed to return the input value");
// Schedule the EventStream to run on the thread's RunLoop
- Interop.EventStream.FSEventStreamScheduleWithRunLoop(_eventStream, runLoop, Interop.RunLoop.kCFRunLoopDefaultMode);
+ Interop.EventStream.FSEventStreamScheduleWithRunLoop(eventStream, runLoop, Interop.RunLoop.kCFRunLoopDefaultMode);
runLoopStarted.Set();
try
private void CancellationCallback()
{
- SafeEventStreamHandle eventStream = _eventStream;
+ SafeEventStreamHandle? eventStream = _eventStream;
if (!_stopping && eventStream != null)
{
_stopping = true;
if (!started)
{
// Try to get the Watcher to raise the error event; if we can't do that, just silently exit since the watcher is gone anyway
- FileSystemWatcher watcher;
- if (_weakWatcher.TryGetTarget(out watcher))
+ if (_weakWatcher.TryGetTarget(out FileSystemWatcher? watcher))
{
// An error occurred while trying to start the run loop so fail out
watcher.OnError(new ErrorEventArgs(new IOException(SR.EventStream_FailedToStart, Marshal.GetLastWin32Error())));
// so as to avoid a rooted cycle that would prevent our processing loop from ever ending
// if the watcher is dropped by the user without being disposed. If we can't get the watcher,
// there's nothing more to do (we can't raise events), so bail.
- FileSystemWatcher watcher;
- if (!_weakWatcher.TryGetTarget(out watcher))
+ if (!_weakWatcher.TryGetTarget(out FileSystemWatcher? watcher))
{
CancellationCallback();
return;
}
- ExecutionContext context = _context;
+ ExecutionContext? context = _context;
if (context is null)
{
// Flow suppressed, just run here
{
ExecutionContext.Run(
context,
- (object o) => ((RunningInstance)o).ProcessEvents(numEvents.ToInt32(), eventPaths, new Span<FSEventStreamEventFlags>(eventFlags, numEvents.ToInt32()), new Span<FSEventStreamEventId>(eventIds, numEvents.ToInt32()), watcher),
+ (object? o) => ((RunningInstance)o!).ProcessEvents(numEvents.ToInt32(), eventPaths, new Span<FSEventStreamEventFlags>(eventFlags, numEvents.ToInt32()), new Span<FSEventStreamEventId>(eventIds, numEvents.ToInt32()), watcher),
this);
}
}
using System.ComponentModel;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.Win32.SafeHandles;
{
state.PreAllocatedOverlapped = new PreAllocatedOverlapped((errorCode, numBytes, overlappedPointer) =>
{
- AsyncReadState state = (AsyncReadState)ThreadPoolBoundHandle.GetNativeOverlappedState(overlappedPointer);
+ AsyncReadState state = (AsyncReadState)ThreadPoolBoundHandle.GetNativeOverlappedState(overlappedPointer)!;
state.ThreadPoolBinding.FreeNativeOverlapped(overlappedPointer);
- if (state.WeakWatcher.TryGetTarget(out FileSystemWatcher watcher))
+ if (state.WeakWatcher.TryGetTarget(out FileSystemWatcher? watcher))
{
watcher.ReadDirectoryChangesCallback(errorCode, numBytes, state);
}
private int _currentSession;
// Unmanaged handle to monitored directory
- private SafeFileHandle _directoryHandle;
+ private SafeFileHandle? _directoryHandle;
- private static bool IsHandleInvalid(SafeFileHandle handle)
+ private static bool IsHandleInvalid([NotNullWhen(false)] SafeFileHandle? handle)
{
return handle == null || handle.IsInvalid || handle.IsClosed;
}
/// </summary>
private unsafe void Monitor(AsyncReadState state)
{
+ Debug.Assert(state.PreAllocatedOverlapped != null);
+
// This method should only ever access the directory handle via the state object passed in, and not access it
// via _directoryHandle. While this function is executing asynchronously, another thread could set
// EnableRaisingEvents to false and then back to true, restarting the FSW and causing a new directory handle
internal byte[] Buffer { get; }
internal SafeFileHandle DirectoryHandle { get; }
internal ThreadPoolBoundHandle ThreadPoolBinding { get; }
- internal PreAllocatedOverlapped PreAllocatedOverlapped { get; set; }
+ internal PreAllocatedOverlapped? PreAllocatedOverlapped { get; set; }
internal WeakReference<FileSystemWatcher> WeakWatcher { get; }
}
}
private bool _disposed;
// Event handlers
- private FileSystemEventHandler _onChangedHandler = null;
- private FileSystemEventHandler _onCreatedHandler = null;
- private FileSystemEventHandler _onDeletedHandler = null;
- private RenamedEventHandler _onRenamedHandler = null;
- private ErrorEventHandler _onErrorHandler = null;
+ private FileSystemEventHandler? _onChangedHandler;
+ private FileSystemEventHandler? _onCreatedHandler;
+ private FileSystemEventHandler? _onDeletedHandler;
+ private RenamedEventHandler? _onRenamedHandler;
+ private ErrorEventHandler? _onErrorHandler;
private const int c_notifyFiltersValidMask = (int)(NotifyFilters.Attributes |
NotifyFilters.CreationTime |
static FileSystemWatcher()
{
int s_notifyFiltersValidMask = 0;
+#pragma warning disable CS8605 // Unboxing a possibly null value
foreach (int enumValue in Enum.GetValues(typeof(NotifyFilters)))
s_notifyFiltersValidMask |= enumValue;
+#pragma warning restore CS8605
Debug.Assert(c_notifyFiltersValidMask == s_notifyFiltersValidMask, "The NotifyFilters enum has changed. The c_notifyFiltersValidMask must be updated to reflect the values of the NotifyFilters enum.");
}
#endif
/// <devdoc>
/// Occurs when a file or directory in the specified <see cref='System.IO.FileSystemWatcher.Path'/> is changed.
/// </devdoc>
- public event FileSystemEventHandler Changed
+ public event FileSystemEventHandler? Changed
{
add
{
/// <devdoc>
/// Occurs when a file or directory in the specified <see cref='System.IO.FileSystemWatcher.Path'/> is created.
/// </devdoc>
- public event FileSystemEventHandler Created
+ public event FileSystemEventHandler? Created
{
add
{
/// <devdoc>
/// Occurs when a file or directory in the specified <see cref='System.IO.FileSystemWatcher.Path'/> is deleted.
/// </devdoc>
- public event FileSystemEventHandler Deleted
+ public event FileSystemEventHandler? Deleted
{
add
{
/// <devdoc>
/// Occurs when the internal buffer overflows.
/// </devdoc>
- public event ErrorEventHandler Error
+ public event ErrorEventHandler? Error
{
add
{
/// Occurs when a file or directory in the specified <see cref='System.IO.FileSystemWatcher.Path'/>
/// is renamed.
/// </devdoc>
- public event RenamedEventHandler Renamed
+ public event RenamedEventHandler? Renamed
{
add
{
private void NotifyRenameEventArgs(WatcherChangeTypes action, ReadOnlySpan<char> name, ReadOnlySpan<char> oldName)
{
// filter if there's no handler or neither new name or old name match a specified pattern
- RenamedEventHandler handler = _onRenamedHandler;
+ RenamedEventHandler? handler = _onRenamedHandler;
if (handler != null &&
(MatchPattern(name) || MatchPattern(oldName)))
{
}
}
- private FileSystemEventHandler GetHandler(WatcherChangeTypes changeType)
+ private FileSystemEventHandler? GetHandler(WatcherChangeTypes changeType)
{
switch (changeType)
{
/// </summary>
private void NotifyFileSystemEventArgs(WatcherChangeTypes changeType, ReadOnlySpan<char> name)
{
- FileSystemEventHandler handler = GetHandler(changeType);
+ FileSystemEventHandler? handler = GetHandler(changeType);
if (handler != null && MatchPattern(name.IsEmpty ? _directory : name))
{
/// </summary>
private void NotifyFileSystemEventArgs(WatcherChangeTypes changeType, string name)
{
- FileSystemEventHandler handler = GetHandler(changeType);
+ FileSystemEventHandler? handler = GetHandler(changeType);
if (handler != null && MatchPattern(string.IsNullOrEmpty(name) ? _directory : name))
{
InvokeOn(e, _onDeletedHandler);
}
- private void InvokeOn(FileSystemEventArgs e, FileSystemEventHandler handler)
+ private void InvokeOn(FileSystemEventArgs e, FileSystemEventHandler? handler)
{
if (handler != null)
{
- ISynchronizeInvoke syncObj = SynchronizingObject;
+ ISynchronizeInvoke? syncObj = SynchronizingObject;
if (syncObj != null && syncObj.InvokeRequired)
syncObj.BeginInvoke(handler, new object[] { this, e });
else
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#", Justification = "Changing from protected to private would be a breaking change")]
protected void OnError(ErrorEventArgs e)
{
- ErrorEventHandler handler = _onErrorHandler;
+ ErrorEventHandler? handler = _onErrorHandler;
if (handler != null)
{
- ISynchronizeInvoke syncObj = SynchronizingObject;
+ ISynchronizeInvoke? syncObj = SynchronizingObject;
if (syncObj != null && syncObj.InvokeRequired)
syncObj.BeginInvoke(handler, new object[] { this, e });
else
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#", Justification = "Changing from protected to private would be a breaking change")]
protected void OnRenamed(RenamedEventArgs e)
{
- RenamedEventHandler handler = _onRenamedHandler;
+ RenamedEventHandler? handler = _onRenamedHandler;
if (handler != null)
{
- ISynchronizeInvoke syncObj = SynchronizingObject;
+ ISynchronizeInvoke? syncObj = SynchronizingObject;
if (syncObj != null && syncObj.InvokeRequired)
syncObj.BeginInvoke(handler, new object[] { this, e });
else
// none is done here, either.
var tcs = new TaskCompletionSource<WaitForChangedResult>();
- FileSystemEventHandler fseh = null;
- RenamedEventHandler reh = null;
+ FileSystemEventHandler? fseh = null;
+ RenamedEventHandler? reh = null;
// Register the event handlers based on what events are desired. The full framework
// doesn't register for the Error event, so this doesn't either.
StartRaisingEvents();
}
- public override ISite Site
+ public override ISite? Site
{
get
{
}
}
- public ISynchronizeInvoke SynchronizingObject { get; set; }
+ public ISynchronizeInvoke? SynchronizingObject { get; set; }
public void BeginInit()
{
/// <devdoc>
/// Initializes a new instance of the <see cref='System.IO.InternalBufferOverflowException'/> class with the error message to be displayed specified.
/// </devdoc>
- public InternalBufferOverflowException(string message) : base(message)
+ public InternalBufferOverflowException(string? message) : base(message)
{
HResult = HResults.InternalBufferOverflow;
}
/// Initializes a new instance of the <see cref='System.IO.InternalBufferOverflowException'/>
/// class with the message to be displayed and the generated inner exception specified.
/// </devdoc>
- public InternalBufferOverflowException(string message, Exception inner) : base(message, inner)
+ public InternalBufferOverflowException(string? message, Exception? inner) : base(message, inner)
{
HResult = HResults.InternalBufferOverflow;
}
/// </devdoc>
public class RenamedEventArgs : FileSystemEventArgs
{
- private readonly string _oldName;
+ private readonly string? _oldName;
private readonly string _oldFullPath;
/// <devdoc>
/// Initializes a new instance of the <see cref='System.IO.RenamedEventArgs'/> class.
/// </devdoc>
- public RenamedEventArgs(WatcherChangeTypes changeType, string directory, string name, string oldName)
+ public RenamedEventArgs(WatcherChangeTypes changeType, string directory, string? name, string? oldName)
: base(changeType, directory, name)
{
_oldName = oldName;
/// <devdoc>
/// Gets the old name of the affected file or directory.
/// </devdoc>
- public string OldName
+ public string? OldName
{
get
{
{
public struct WaitForChangedResult
{
- internal WaitForChangedResult(WatcherChangeTypes changeType, string name, string oldName, bool timedOut)
+ internal WaitForChangedResult(WatcherChangeTypes changeType, string? name, string? oldName, bool timedOut)
{
ChangeType = changeType;
Name = name;
new WaitForChangedResult(changeType: 0, name: null, oldName: null, timedOut: true);
public WatcherChangeTypes ChangeType { get; set; }
- public string Name { get; set; }
- public string OldName { get; set; }
+ public string? Name { get; set; }
+ public string? OldName { get; set; }
public bool TimedOut { get; set; }
}
}
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetsNetStandard)' == 'true' and '$(OSGroup)' == 'AnyOS'">SR.PlatformNotSupported_IOPorts</GeneratePlatformNotSupportedAssemblyMessage>
<DefineConstants>$(DefineConstants);NOSPAN</DefineConstants>
<IncludeDllSafeSearchPathAttribute>true</IncludeDllSafeSearchPathAttribute>
+ <Nullable>annotations</Nullable>
<Configurations>net461-Windows_NT-Debug;net461-Windows_NT-Release;netfx-Windows_NT-Debug;netfx-Windows_NT-Release;netstandard2.0-Debug;netstandard2.0-Linux-Debug;netstandard2.0-Linux-Release;netstandard2.0-OSX-Debug;netstandard2.0-OSX-Release;netstandard2.0-Release;netstandard2.0-Windows_NT-Debug;netstandard2.0-Windows_NT-Release</Configurations>
</PropertyGroup>
<ItemGroup Condition="'$(TargetsNetStandard)' == 'true' and '$(OSGroup)' != 'AnyOS'">