CmdPal: Null pattern matching based on is expression rather than overridable operators (#40972)

What the title says. 😄 

Rather than relying on the potentially overloaded `!=` or `==` operators
when checking for null, now we'll use the `is` expression (possibly
combined with the `not` operator) to ensure correct checking. Probably
overkill for many of these classes, but decided to err on the side of
consistency. Would matter more on classes that may be inherited or
extended.

Using `is` and `is not` will provide us a guarantee that no
user-overloaded equality operators (`==`/`!=`) is invoked when a
`expression is null` is evaluated.

In code form, changed all instances of:

```c#
something != null

something == null
```

to:

```c#
something is not null

something is null
```

The one exception was checking null on a `KeyChord`. `KeyChord` is a
struct which is never null so VS will raise an error when trying this
versus just providing a warning when using `keyChord != null`. In
reality, we shouldn't do this check because it can't ever be null. In
the case of a `KeyChord` it **would** be a `KeyChord` equivalent to:

```c#
KeyChord keyChord = new ()
{
    Modifiers = 0,
    Vkey = 0,
    ScanCode = 0
};
```
This commit is contained in:
Michael Jolley
2025-08-18 06:07:28 -05:00
committed by GitHub
parent efb48aa163
commit 6acb793184
138 changed files with 395 additions and 431 deletions

View File

@@ -10,7 +10,6 @@ using Microsoft.CmdPal.UI.Views;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Input;
using Windows.System;
namespace Microsoft.CmdPal.UI.Controls;
@@ -50,7 +49,7 @@ public sealed partial class CommandBar : UserControl,
return;
}
if (message.Element == null)
if (message.Element is null)
{
_ = DispatcherQueue.TryEnqueue(
() =>

View File

@@ -44,7 +44,7 @@ public sealed partial class ContentFormControl : UserControl
// 5% BODGY: if we set this multiple times over the lifetime of the app,
// then the second call will explode, because "CardOverrideStyles is already the child of another element".
// SO only set this once.
if (_renderer.OverrideStyles == null)
if (_renderer.OverrideStyles is null)
{
_renderer.OverrideStyles = CardOverrideStyles;
}
@@ -55,19 +55,19 @@ public sealed partial class ContentFormControl : UserControl
private void AttachViewModel(ContentFormViewModel? vm)
{
if (_viewModel != null)
if (_viewModel is not null)
{
_viewModel.PropertyChanged -= ViewModel_PropertyChanged;
}
_viewModel = vm;
if (_viewModel != null)
if (_viewModel is not null)
{
_viewModel.PropertyChanged += ViewModel_PropertyChanged;
var c = _viewModel.Card;
if (c != null)
if (c is not null)
{
DisplayCard(c);
}
@@ -76,7 +76,7 @@ public sealed partial class ContentFormControl : UserControl
private void ViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (ViewModel == null)
if (ViewModel is null)
{
return;
}
@@ -84,7 +84,7 @@ public sealed partial class ContentFormControl : UserControl
if (e.PropertyName == nameof(ViewModel.Card))
{
var c = ViewModel.Card;
if (c != null)
if (c is not null)
{
DisplayCard(c);
}
@@ -95,7 +95,7 @@ public sealed partial class ContentFormControl : UserControl
{
_renderedCard = _renderer.RenderAdaptiveCard(result.AdaptiveCard);
ContentGrid.Children.Clear();
if (_renderedCard.FrameworkElement != null)
if (_renderedCard.FrameworkElement is not null)
{
ContentGrid.Children.Add(_renderedCard.FrameworkElement);
@@ -148,7 +148,7 @@ public sealed partial class ContentFormControl : UserControl
// Recursively check children
var result = FindFirstFocusableElement(child);
if (result != null)
if (result is not null)
{
return result;
}

View File

@@ -31,7 +31,7 @@ public sealed partial class ContextMenu : UserControl,
WeakReferenceMessenger.Default.Register<UpdateCommandBarMessage>(this);
WeakReferenceMessenger.Default.Register<TryCommandKeybindingMessage>(this);
if (ViewModel != null)
if (ViewModel is not null)
{
ViewModel.PropertyChanged += ViewModel_PropertyChanged;
}

View File

@@ -91,7 +91,7 @@ public partial class IconBox : ContentControl
{
if (d is IconBox @this)
{
if (e.NewValue == null)
if (e.NewValue is null)
{
@this.Source = null;
}
@@ -104,7 +104,7 @@ public partial class IconBox : ContentControl
var requestedTheme = @this.ActualTheme;
var eventArgs = new SourceRequestedEventArgs(e.NewValue, requestedTheme);
if (@this.SourceRequested != null)
if (@this.SourceRequested is not null)
{
await @this.SourceRequested.InvokeAsync(@this, eventArgs);
@@ -142,7 +142,7 @@ public partial class IconBox : ContentControl
iconData = requestedTheme == ElementTheme.Light ? info.Light : info.Dark;
}
if (iconData != null &&
if (iconData is not null &&
@this.Source is FontIconSource)
{
if (!string.IsNullOrEmpty(iconData.Icon) && iconData.Icon.Length <= 2)

View File

@@ -2,7 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
@@ -80,12 +79,12 @@ public sealed partial class KeyVisual : Control
private void Update()
{
if (_keyVisual == null)
if (_keyVisual is null)
{
return;
}
if (_keyVisual.Content != null)
if (_keyVisual.Content is not null)
{
if (_keyVisual.Content.GetType() == typeof(string))
{

View File

@@ -51,13 +51,13 @@ public sealed partial class SearchBar : UserControl,
//// TODO: If the Debounce timer hasn't fired, we may want to store the current Filter in the OldValue/prior VM, but we don't want that to go actually do work...
var @this = (SearchBar)d;
if (@this != null
if (@this is not null
&& e.OldValue is PageViewModel old)
{
old.PropertyChanged -= @this.Page_PropertyChanged;
}
if (@this != null
if (@this is not null
&& e.NewValue is PageViewModel page)
{
// TODO: In some cases we probably want commands to clear a filter
@@ -85,7 +85,7 @@ public sealed partial class SearchBar : UserControl,
{
this.FilterBox.Text = string.Empty;
if (CurrentPageViewModel != null)
if (CurrentPageViewModel is not null)
{
CurrentPageViewModel.Filter = string.Empty;
}
@@ -143,7 +143,7 @@ public sealed partial class SearchBar : UserControl,
FilterBox.Text = string.Empty;
// hack TODO GH #245
if (CurrentPageViewModel != null)
if (CurrentPageViewModel is not null)
{
CurrentPageViewModel.Filter = FilterBox.Text;
}
@@ -154,7 +154,7 @@ public sealed partial class SearchBar : UserControl,
else if (e.Key == VirtualKey.Back)
{
// hack TODO GH #245
if (CurrentPageViewModel != null)
if (CurrentPageViewModel is not null)
{
CurrentPageViewModel.Filter = FilterBox.Text;
}
@@ -318,7 +318,7 @@ public sealed partial class SearchBar : UserControl,
}
// Actually plumb Filtering to the view model
if (CurrentPageViewModel != null)
if (CurrentPageViewModel is not null)
{
CurrentPageViewModel.Filter = FilterBox.Text;
}

View File

@@ -39,13 +39,13 @@ public sealed partial class ShortcutControl : UserControl, IDisposable, IRecipie
private static void OnAllowDisableChanged(DependencyObject d, DependencyPropertyChangedEventArgs? e)
{
var me = d as ShortcutControl;
if (me == null)
if (me is null)
{
return;
}
var description = me.c?.FindDescendant<TextBlock>();
if (description == null)
if (description is null)
{
return;
}
@@ -431,7 +431,7 @@ public sealed partial class ShortcutControl : UserControl, IDisposable, IRecipie
private void ShortcutDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
if (lastValidSettings != null && ComboIsValid(lastValidSettings))
if (lastValidSettings is not null && ComboIsValid(lastValidSettings))
{
HotkeySettings = lastValidSettings with { };
}
@@ -458,7 +458,7 @@ public sealed partial class ShortcutControl : UserControl, IDisposable, IRecipie
private static bool ComboIsValid(HotkeySettings? settings)
{
return settings != null && (settings.IsValid() || settings.IsEmpty());
return settings is not null && (settings.IsValid() || settings.IsEmpty());
}
public void Receive(WindowActivatedEventArgs message) => DoWindowActivated(message);
@@ -466,12 +466,12 @@ public sealed partial class ShortcutControl : UserControl, IDisposable, IRecipie
private void DoWindowActivated(WindowActivatedEventArgs args)
{
args.Handled = true;
if (args.WindowActivationState != WindowActivationState.Deactivated && (hook == null || hook.GetDisposedState() == true))
if (args.WindowActivationState != WindowActivationState.Deactivated && (hook is null || hook.GetDisposedState() == true))
{
// If the PT settings window gets focussed/activated again, we enable the keyboard hook to catch the keyboard input.
hook = new HotkeySettingsControlHook(Hotkey_KeyDown, Hotkey_KeyUp, Hotkey_IsActive, FilterAccessibleKeyboardEvents);
}
else if (args.WindowActivationState == WindowActivationState.Deactivated && hook != null && hook.GetDisposedState() == false)
else if (args.WindowActivationState == WindowActivationState.Deactivated && hook is not null && hook.GetDisposedState() == false)
{
// If the PT settings window lost focus/activation, we disable the keyboard hook to allow keyboard input on other windows.
hook.Dispose();
@@ -490,7 +490,7 @@ public sealed partial class ShortcutControl : UserControl, IDisposable, IRecipie
{
if (disposing)
{
if (hook != null)
if (hook is not null)
{
hook.Dispose();
}

View File

@@ -84,7 +84,7 @@ public partial class Tag : Control
return;
}
if (tag.ForegroundColor != null &&
if (tag.ForegroundColor is not null &&
OptionalColorBrushCacheProvider.Convert(tag.ForegroundColor.Value) is SolidColorBrush brush)
{
tag.Foreground = brush;
@@ -114,7 +114,7 @@ public partial class Tag : Control
return;
}
if (tag.BackgroundColor != null &&
if (tag.BackgroundColor is not null &&
OptionalColorBrushCacheProvider.Convert(tag.BackgroundColor.Value) is SolidColorBrush brush)
{
tag.Background = brush;

View File

@@ -74,7 +74,7 @@ public sealed partial class ListPage : Page,
WeakReferenceMessenger.Default.Unregister<ActivateSelectedListItemMessage>(this);
WeakReferenceMessenger.Default.Unregister<ActivateSecondaryCommandMessage>(this);
if (ViewModel != null)
if (ViewModel is not null)
{
ViewModel.PropertyChanged -= ViewModel_PropertyChanged;
ViewModel.ItemsUpdated -= Page_ItemsUpdated;
@@ -142,13 +142,13 @@ public sealed partial class ListPage : Page,
// here, then in Page_ItemsUpdated trying to select that cached item if
// it's in the list (otherwise, clear the cache), but that seems
// aggressively BODGY for something that mostly just works today.
if (ItemsList.SelectedItem != null)
if (ItemsList.SelectedItem is not null)
{
ItemsList.ScrollIntoView(ItemsList.SelectedItem);
// Automation notification for screen readers
var listViewPeer = Microsoft.UI.Xaml.Automation.Peers.ListViewAutomationPeer.CreatePeerForElement(ItemsList);
if (listViewPeer != null && li != null)
if (listViewPeer is not null && li is not null)
{
var notificationText = li.Title;
listViewPeer.RaiseNotificationEvent(
@@ -165,7 +165,7 @@ public sealed partial class ListPage : Page,
// Find the ScrollViewer in the ListView
var listViewScrollViewer = FindScrollViewer(this.ItemsList);
if (listViewScrollViewer != null)
if (listViewScrollViewer is not null)
{
listViewScrollViewer.ViewChanged += ListViewScrollViewer_ViewChanged;
}
@@ -174,7 +174,7 @@ public sealed partial class ListPage : Page,
private void ListViewScrollViewer_ViewChanged(object? sender, ScrollViewerViewChangedEventArgs e)
{
var scrollView = sender as ScrollViewer;
if (scrollView == null)
if (scrollView is null)
{
return;
}
@@ -256,7 +256,7 @@ public sealed partial class ListPage : Page,
page.PropertyChanged += @this.ViewModel_PropertyChanged;
page.ItemsUpdated += @this.Page_ItemsUpdated;
}
else if (e.NewValue == null)
else if (e.NewValue is null)
{
Logger.LogDebug("cleared view model");
}
@@ -274,7 +274,7 @@ public sealed partial class ListPage : Page,
// ItemsList_SelectionChanged again to give us another chance to change
// the selection from null -> something. Better to just update the
// selection once, at the end of all the updating.
if (ItemsList.SelectedItem == null)
if (ItemsList.SelectedItem is null)
{
ItemsList.SelectedIndex = 0;
}
@@ -307,7 +307,7 @@ public sealed partial class ListPage : Page,
{
var child = VisualTreeHelper.GetChild(parent, i);
var result = FindScrollViewer(child);
if (result != null)
if (result is not null)
{
return result;
}
@@ -329,7 +329,7 @@ public sealed partial class ListPage : Page,
_ => (null, null),
};
if (item == null || element == null)
if (item is null || element is null)
{
return;
}

View File

@@ -2,13 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CmdPal.Ext.Bookmarks;
using Microsoft.UI.Xaml.Documents;
using Microsoft.Win32;
namespace Microsoft.CmdPal.UI.Helpers;
@@ -63,7 +56,7 @@ internal static class GpoValueChecker
{
using (RegistryKey? key = rootKey.OpenSubKey(subKeyPath, false))
{
if (key == null)
if (key is null)
{
return null;
}

View File

@@ -4,7 +4,6 @@
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.UI.Controls;
using Microsoft.CmdPal.UI.Helpers;
namespace Microsoft.CmdPal.UI.Helpers;
@@ -19,7 +18,7 @@ public static partial class IconCacheProvider
public static async void SourceRequested(IconBox sender, SourceRequestedEventArgs args)
#pragma warning restore IDE0060 // Remove unused parameter
{
if (args.Key == null)
if (args.Key is null)
{
return;
}

View File

@@ -28,7 +28,7 @@ public sealed class IconCacheService(DispatcherQueue dispatcherQueue)
var source = IconPathConverter.IconSourceMUX(icon.Icon, false);
return source;
}
else if (icon.Data != null)
else if (icon.Data is not null)
{
try
{
@@ -49,7 +49,7 @@ public sealed class IconCacheService(DispatcherQueue dispatcherQueue)
private async Task<IconSource?> StreamToIconSource(IRandomAccessStreamReference iconStreamRef)
{
if (iconStreamRef == null)
if (iconStreamRef is null)
{
return null;
}

View File

@@ -50,7 +50,7 @@ internal sealed partial class TrayIconService
{
if (showSystemTrayIcon ?? _settingsModel.ShowSystemTrayIcon)
{
if (_window == null)
if (_window is null)
{
_window = new Window();
_hwnd = new HWND(WindowNative.GetWindowHandle(_window));
@@ -64,7 +64,7 @@ internal sealed partial class TrayIconService
_originalWndProc = Marshal.GetDelegateForFunctionPointer<WNDPROC>(PInvoke.SetWindowLongPtr(_hwnd, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC, hotKeyPrcPointer));
}
if (_trayIconData == null)
if (_trayIconData is null)
{
// We need to stash this handle, so it doesn't clean itself up. If
// explorer restarts, we'll come back through here, and we don't
@@ -88,7 +88,7 @@ internal sealed partial class TrayIconService
// Add the notification icon
PInvoke.Shell_NotifyIcon(NOTIFY_ICON_MESSAGE.NIM_ADD, in d);
if (_popupMenu == null)
if (_popupMenu is null)
{
_popupMenu = PInvoke.CreatePopupMenu_SafeHandle();
PInvoke.InsertMenu(_popupMenu, 0, MENU_ITEM_FLAGS.MF_BYPOSITION | MENU_ITEM_FLAGS.MF_STRING, PInvoke.WM_USER + 1, RS_.GetString("TrayMenu_Settings"));
@@ -103,7 +103,7 @@ internal sealed partial class TrayIconService
public void Destroy()
{
if (_trayIconData != null)
if (_trayIconData is not null)
{
var d = (NOTIFYICONDATAW)_trayIconData;
if (PInvoke.Shell_NotifyIcon(NOTIFY_ICON_MESSAGE.NIM_DELETE, in d))
@@ -112,19 +112,19 @@ internal sealed partial class TrayIconService
}
}
if (_popupMenu != null)
if (_popupMenu is not null)
{
_popupMenu.Close();
_popupMenu = null;
}
if (_largeIcon != null)
if (_largeIcon is not null)
{
_largeIcon.Close();
_largeIcon = null;
}
if (_window != null)
if (_window is not null)
{
_window.Close();
_window = null;
@@ -167,7 +167,7 @@ internal sealed partial class TrayIconService
// WM_WINDOWPOSCHANGING which is always received on explorer startup sequence.
case PInvoke.WM_WINDOWPOSCHANGING:
{
if (_trayIconData == null)
if (_trayIconData is null)
{
SetupTrayIcon();
}
@@ -189,7 +189,7 @@ internal sealed partial class TrayIconService
{
case PInvoke.WM_RBUTTONUP:
{
if (_popupMenu != null)
if (_popupMenu is not null)
{
PInvoke.GetCursorPos(out var cursorPos);
PInvoke.SetForegroundWindow(_hwnd);

View File

@@ -46,7 +46,7 @@ public static class TypedEventHandlerExtensions
#pragma warning restore CA1715 // Identifiers should have correct prefix
where R : DeferredEventArgs
{
if (eventHandler == null)
if (eventHandler is null)
{
return Task.CompletedTask;
}

View File

@@ -13,7 +13,7 @@ internal sealed partial class WindowHelper
UserNotificationState state;
// https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ne-shellapi-query_user_notification_state
if (Marshal.GetExceptionForHR(NativeMethods.SHQueryUserNotificationState(out state)) == null)
if (Marshal.GetExceptionForHR(NativeMethods.SHQueryUserNotificationState(out state)) is null)
{
if (state == UserNotificationState.QUNS_RUNNING_D3D_FULL_SCREEN ||
state == UserNotificationState.QUNS_BUSY ||

View File

@@ -384,7 +384,7 @@ public sealed partial class MainWindow : WindowEx,
private void DisposeAcrylic()
{
if (_acrylicController != null)
if (_acrylicController is not null)
{
_acrylicController.Dispose();
_acrylicController = null!;
@@ -459,7 +459,7 @@ public sealed partial class MainWindow : WindowEx,
PowerToysTelemetry.Log.WriteEvent(new CmdPalDismissedOnLostFocus());
}
if (_configurationSource != null)
if (_configurationSource is not null)
{
_configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;
}
@@ -467,7 +467,7 @@ public sealed partial class MainWindow : WindowEx,
public void HandleLaunch(AppActivationArguments? activatedEventArgs)
{
if (activatedEventArgs == null)
if (activatedEventArgs is null)
{
Summon(string.Empty);
return;
@@ -535,7 +535,7 @@ public sealed partial class MainWindow : WindowEx,
UnregisterHotkeys();
var globalHotkey = settings.Hotkey;
if (globalHotkey != null)
if (globalHotkey is not null)
{
if (settings.UseLowLevelGlobalHotkey)
{
@@ -565,7 +565,7 @@ public sealed partial class MainWindow : WindowEx,
{
var key = commandHotkey.Hotkey;
if (key != null)
if (key is not null)
{
if (settings.UseLowLevelGlobalHotkey)
{

View File

@@ -24,7 +24,7 @@ public sealed partial class LoadingPage : Page
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is ShellViewModel shellVM
&& shellVM.LoadCommand != null)
&& shellVM.LoadCommand is not null)
{
// This will load the built-in commands, then navigate to the main page.
// Once the mainpage loads, we'll start loading extensions.

View File

@@ -171,7 +171,7 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
// This gets called from the UI thread
private async Task HandleConfirmArgsOnUiThread(IConfirmationArgs? args)
{
if (args == null)
if (args is null)
{
return;
}
@@ -236,7 +236,7 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
public void OpenSettings()
{
if (_settingsWindow == null)
if (_settingsWindow is null)
{
_settingsWindow = new SettingsWindow();
}
@@ -324,7 +324,7 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
// command from our list of toplevel commands.
var tlcManager = App.Current.Services.GetService<TopLevelCommandManager>()!;
var topLevelCommand = tlcManager.LookupCommand(commandId);
if (topLevelCommand != null)
if (topLevelCommand is not null)
{
var command = topLevelCommand.CommandViewModel.Model.Unsafe;
var isPage = command is not IInvokableCommand;

View File

@@ -100,7 +100,7 @@ internal sealed class PowerToysRootPageService : IRootPageService
_activeExtension = extension;
var extensionWinRtObject = _activeExtension?.GetExtensionObject();
if (extensionWinRtObject != null)
if (extensionWinRtObject is not null)
{
try
{