Skip to content

Commit c40c6e7

Browse files
[core] use StringComparison.Ordinal everywhere (#4988)
Context: https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1307 Context: https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1309 Context: dotnet/runtime#43956 I was reviewing `dotnet trace` output of the .NET Podcast app: 6.32ms Microsoft.Maui.Controls!Microsoft.Maui.Controls.ShellNavigationManager.GetNavigationState 3.82ms Microsoft.Maui.Controls!Microsoft.Maui.Controls.ShellUriHandler.FormatUri The bulk of this time is spent in `string.StartsWith()`, doing a culture-aware string comparison? 3.82ms System.Private.CoreLib!System.String.StartsWith 2.57ms System.Private.CoreLib!System.Globalization.CultureInfo.get_CurrentCulture This looks to be showing the cost of the 1st culture-aware comparision plus any time making these slower string comparisons. It would be ideal if project templates did not even hit `CultureInfo.get_CurrentCulture`. To solve this, let's add to the `.editorconfig` file: dotnet_diagnostic.CA1307.severity = error dotnet_diagnostic.CA1309.severity = error And then fix all the places errors appear. There are some complications in projects that use `netstandard2.0`: 1. For `Contains()` use `IndexOf()` instead. 2. Use `#if NETSTANDARD2_0` for `GetHashCode()` or `Replace()`. Use the `char` overload of `string.Replace()` where possible. 3. Generally, `InvariantCulture` should not be used. After these changes, the `FormatUri` method disappears completely from the trace, and we instead get: 2.88ms Microsoft.Maui.Controls!Microsoft.Maui.Controls.ShellNavigationManager.GetNavigationState I suspect this saves ~3.44ms for any MAUI app startup, and a small amount more depending on the number of string comparisions happening.
1 parent 439b52c commit c40c6e7

File tree

88 files changed

+248
-182
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+248
-182
lines changed

.editorconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ indent_style = tab
2323
# https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1416
2424
dotnet_diagnostic.CA1416.severity = none
2525

26+
# Code analyzers
27+
dotnet_diagnostic.CA1307.severity = error
28+
dotnet_diagnostic.CA1309.severity = error
29+
2630
# Modifier preferences
2731
dotnet_style_require_accessibility_modifiers = never:suggestion
2832

src/BlazorWebView/src/Maui/Windows/WinUIWebViewManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ protected override async Task HandleWebResourceRequest(CoreWebView2WebResourceRe
9191
{
9292
relativePath = _hostPageRelativePath;
9393
}
94-
relativePath = Path.Combine(_contentRootDir, relativePath.Replace("/", "\\"));
94+
relativePath = Path.Combine(_contentRootDir, relativePath.Replace('/', '\\'));
9595

9696
var winUIItem = await Package.Current.InstalledLocation.TryGetItemAsync(relativePath);
9797
if (winUIItem != null)

src/BlazorWebView/src/SharedSource/QueryStringHelper.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#nullable enable
55

6+
using System;
7+
68
namespace Microsoft.AspNetCore.Components.WebView
79
{
810
internal static class QueryStringHelper
@@ -13,7 +15,7 @@ public static string RemovePossibleQueryString(string? url)
1315
{
1416
return string.Empty;
1517
}
16-
var indexOfQueryString = url.IndexOf('?');
18+
var indexOfQueryString = url.IndexOf('?', StringComparison.Ordinal);
1719
return (indexOfQueryString == -1)
1820
? url
1921
: url.Substring(0, indexOfQueryString);

src/Compatibility/ControlGallery/src/Android/TestCloudService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using Microsoft.Maui.Controls.Compatibility.ControlGallery;
23

34
namespace Microsoft.Maui.Controls.Compatibility.ControlGallery.Android
@@ -8,7 +9,7 @@ public bool IsOnTestCloud()
89
{
910
var isInTestCloud = System.Environment.GetEnvironmentVariable("XAMARIN_TEST_CLOUD");
1011

11-
return isInTestCloud != null && isInTestCloud.Equals("1");
12+
return isInTestCloud != null && isInTestCloud.Equals("1", StringComparison.Ordinal);
1213
}
1314

1415
public string GetTestCloudDeviceName()

src/Compatibility/ControlGallery/src/Core/GalleryPages/CollectionViewGalleries/DemoFilteredItemSource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public DemoFilteredItemSource(int count = 50, Func<string, CollectionViewGallery
4040
private bool ItemMatches(string filter, CollectionViewGalleryTestItem item)
4141
{
4242
filter = filter ?? "";
43-
return item.Caption.ToLower().Contains(filter?.ToLower());
43+
return item.Caption.IndexOf(filter, StringComparison.OrdinalIgnoreCase) != -1;
4444
}
4545

4646
public void FilterItems(string filter)

src/Compatibility/ControlGallery/src/UITests.Shared/Utilities/ParsingUtils.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public static Font ParseUIFont(string font)
1515

1616
// Logger.LogLine ("TEST PARSING");
1717

18-
if (font.Contains("font-weight: bold;"))
18+
if (font.IndexOf("font-weight: bold;", StringComparison.Ordinal) != -1)
1919
{
2020
// Logger.LogLine ("Found Bold");
2121
fontAttrs = FontAttributes.Bold;

src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public static MauiApp CreateMauiApp()
2626
.AddWindows(windows => windows
2727
.OnLaunching((_, e) =>
2828
{
29-
if (!string.IsNullOrWhiteSpace(e.Arguments) && e.Arguments.Contains("RunningAsUITests"))
29+
if (!string.IsNullOrWhiteSpace(e.Arguments) && e.Arguments.Contains("RunningAsUITests", StringComparison.Ordinal))
3030
{
3131
App.RunningAsUITests = true;
3232
ControlGallery.App.PreloadTestCasesIssuesList = false;

src/Compatibility/ControlGallery/src/iOS/AppDelegate.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public bool IsOnTestCloud()
8989
{
9090
var isInTestCloud = Environment.GetEnvironmentVariable("XAMARIN_TEST_CLOUD");
9191

92-
return isInTestCloud != null && isInTestCloud.Equals("1");
92+
return isInTestCloud != null && isInTestCloud.Equals("1", StringComparison.Ordinal);
9393
}
9494

9595
public string GetTestCloudDeviceName()

src/Compatibility/Core/src/Android/BorderBackgroundManager.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -219,17 +219,17 @@ void BorderElementPropertyChanged(object sender, PropertyChangedEventArgs e)
219219
return;
220220
}
221221

222-
if (e.PropertyName.Equals(Button.BorderColorProperty.PropertyName) ||
223-
e.PropertyName.Equals(Button.BorderWidthProperty.PropertyName) ||
224-
e.PropertyName.Equals(Button.CornerRadiusProperty.PropertyName) ||
225-
e.PropertyName.Equals(VisualElement.BackgroundColorProperty.PropertyName) ||
226-
e.PropertyName.Equals(VisualElement.BackgroundProperty.PropertyName) ||
227-
e.PropertyName.Equals(Specifics.Button.UseDefaultPaddingProperty.PropertyName) ||
228-
e.PropertyName.Equals(Specifics.Button.UseDefaultShadowProperty.PropertyName) ||
229-
e.PropertyName.Equals(Specifics.ImageButton.IsShadowEnabledProperty.PropertyName) ||
230-
e.PropertyName.Equals(Specifics.ImageButton.ShadowColorProperty.PropertyName) ||
231-
e.PropertyName.Equals(Specifics.ImageButton.ShadowOffsetProperty.PropertyName) ||
232-
e.PropertyName.Equals(Specifics.ImageButton.ShadowRadiusProperty.PropertyName))
222+
if (e.PropertyName.Equals(Button.BorderColorProperty.PropertyName, StringComparison.Ordinal) ||
223+
e.PropertyName.Equals(Button.BorderWidthProperty.PropertyName, StringComparison.Ordinal) ||
224+
e.PropertyName.Equals(Button.CornerRadiusProperty.PropertyName, StringComparison.Ordinal) ||
225+
e.PropertyName.Equals(VisualElement.BackgroundColorProperty.PropertyName, StringComparison.Ordinal) ||
226+
e.PropertyName.Equals(VisualElement.BackgroundProperty.PropertyName, StringComparison.Ordinal) ||
227+
e.PropertyName.Equals(Specifics.Button.UseDefaultPaddingProperty.PropertyName, StringComparison.Ordinal) ||
228+
e.PropertyName.Equals(Specifics.Button.UseDefaultShadowProperty.PropertyName, StringComparison.Ordinal) ||
229+
e.PropertyName.Equals(Specifics.ImageButton.IsShadowEnabledProperty.PropertyName, StringComparison.Ordinal) ||
230+
e.PropertyName.Equals(Specifics.ImageButton.ShadowColorProperty.PropertyName, StringComparison.Ordinal) ||
231+
e.PropertyName.Equals(Specifics.ImageButton.ShadowOffsetProperty.PropertyName, StringComparison.Ordinal) ||
232+
e.PropertyName.Equals(Specifics.ImageButton.ShadowRadiusProperty.PropertyName, StringComparison.Ordinal))
233233
{
234234
Reset();
235235
UpdateDrawable();

src/Compatibility/Core/src/Android/Renderers/DatePickerRenderer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ void SetDate(DateTime date)
160160
{
161161
EditText.Text = date.ToShortDateString();
162162
}
163-
else if (Element.Format.Contains('/'))
163+
else if (Element.Format.Contains('/', StringComparison.Ordinal))
164164
{
165165
EditText.Text = date.ToString(Element.Format, CultureInfo.InvariantCulture);
166166
}

0 commit comments

Comments
 (0)