From 175f317c5ed85a9a5b26498ef822aa0038af7f6e Mon Sep 17 00:00:00 2001 From: "J. Daniel Smith" Date: Thu, 17 Nov 2022 21:08:00 -0500 Subject: [PATCH 1/5] .NET 7.0 --- StringComparisonString.sln | 26 +++++++++---------- .../StringComparisonString.csproj | 11 +++----- .../CompareToUnitTest.cs | 0 .../CtorUnitTest.cs | 0 .../EqualsUnitTest.cs | 0 .../GetHashCodeUnitTest.cs | 0 .../IndexOfUnitTest.cs | 6 ++--- .../StringComparisonStringTestProject.csproj | 13 +++++----- StringComparisonStringTestProject/Usings.cs | 1 + 9 files changed, 27 insertions(+), 30 deletions(-) rename {StringComparisonStringUnitTest => StringComparisonStringTestProject}/CompareToUnitTest.cs (100%) rename {StringComparisonStringUnitTest => StringComparisonStringTestProject}/CtorUnitTest.cs (100%) rename {StringComparisonStringUnitTest => StringComparisonStringTestProject}/EqualsUnitTest.cs (100%) rename {StringComparisonStringUnitTest => StringComparisonStringTestProject}/GetHashCodeUnitTest.cs (100%) rename {StringComparisonStringUnitTest => StringComparisonStringTestProject}/IndexOfUnitTest.cs (71%) rename StringComparisonStringUnitTest/StringComparisonStringUnitTest.csproj => StringComparisonStringTestProject/StringComparisonStringTestProject.csproj (58%) create mode 100644 StringComparisonStringTestProject/Usings.cs diff --git a/StringComparisonString.sln b/StringComparisonString.sln index c16f9f8..290529d 100644 --- a/StringComparisonString.sln +++ b/StringComparisonString.sln @@ -1,11 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30711.63 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33110.190 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StringComparisonString", "StringComparisonString\StringComparisonString.csproj", "{67A2263A-15B5-4184-9AFC-6A634A6F3477}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StringComparisonString", "StringComparisonString\StringComparisonString.csproj", "{43AA80FC-3775-48EF-8BDE-47FC126222F1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StringComparisonStringUnitTest", "StringComparisonStringUnitTest\StringComparisonStringUnitTest.csproj", "{05C466E6-114B-4A33-9F46-1B56489E9335}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StringComparisonStringTestProject", "StringComparisonStringTestProject\StringComparisonStringTestProject.csproj", "{D7680924-FEC5-4A05-A0F6-571BE2A1B561}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,19 +13,19 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {67A2263A-15B5-4184-9AFC-6A634A6F3477}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {67A2263A-15B5-4184-9AFC-6A634A6F3477}.Debug|Any CPU.Build.0 = Debug|Any CPU - {67A2263A-15B5-4184-9AFC-6A634A6F3477}.Release|Any CPU.ActiveCfg = Release|Any CPU - {67A2263A-15B5-4184-9AFC-6A634A6F3477}.Release|Any CPU.Build.0 = Release|Any CPU - {05C466E6-114B-4A33-9F46-1B56489E9335}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {05C466E6-114B-4A33-9F46-1B56489E9335}.Debug|Any CPU.Build.0 = Debug|Any CPU - {05C466E6-114B-4A33-9F46-1B56489E9335}.Release|Any CPU.ActiveCfg = Release|Any CPU - {05C466E6-114B-4A33-9F46-1B56489E9335}.Release|Any CPU.Build.0 = Release|Any CPU + {43AA80FC-3775-48EF-8BDE-47FC126222F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43AA80FC-3775-48EF-8BDE-47FC126222F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43AA80FC-3775-48EF-8BDE-47FC126222F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43AA80FC-3775-48EF-8BDE-47FC126222F1}.Release|Any CPU.Build.0 = Release|Any CPU + {D7680924-FEC5-4A05-A0F6-571BE2A1B561}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D7680924-FEC5-4A05-A0F6-571BE2A1B561}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D7680924-FEC5-4A05-A0F6-571BE2A1B561}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D7680924-FEC5-4A05-A0F6-571BE2A1B561}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {88F9CD28-92F0-49DD-8AED-9A9B2FA8C639} + SolutionGuid = {8951358D-25E1-4C76-9C19-30ACFF19E7B4} EndGlobalSection EndGlobal diff --git a/StringComparisonString/StringComparisonString.csproj b/StringComparisonString/StringComparisonString.csproj index fbdbe81..cfadb03 100644 --- a/StringComparisonString/StringComparisonString.csproj +++ b/StringComparisonString/StringComparisonString.csproj @@ -1,12 +1,9 @@ - + - net6.0 - True - - - - true + net7.0 + enable + enable diff --git a/StringComparisonStringUnitTest/CompareToUnitTest.cs b/StringComparisonStringTestProject/CompareToUnitTest.cs similarity index 100% rename from StringComparisonStringUnitTest/CompareToUnitTest.cs rename to StringComparisonStringTestProject/CompareToUnitTest.cs diff --git a/StringComparisonStringUnitTest/CtorUnitTest.cs b/StringComparisonStringTestProject/CtorUnitTest.cs similarity index 100% rename from StringComparisonStringUnitTest/CtorUnitTest.cs rename to StringComparisonStringTestProject/CtorUnitTest.cs diff --git a/StringComparisonStringUnitTest/EqualsUnitTest.cs b/StringComparisonStringTestProject/EqualsUnitTest.cs similarity index 100% rename from StringComparisonStringUnitTest/EqualsUnitTest.cs rename to StringComparisonStringTestProject/EqualsUnitTest.cs diff --git a/StringComparisonStringUnitTest/GetHashCodeUnitTest.cs b/StringComparisonStringTestProject/GetHashCodeUnitTest.cs similarity index 100% rename from StringComparisonStringUnitTest/GetHashCodeUnitTest.cs rename to StringComparisonStringTestProject/GetHashCodeUnitTest.cs diff --git a/StringComparisonStringUnitTest/IndexOfUnitTest.cs b/StringComparisonStringTestProject/IndexOfUnitTest.cs similarity index 71% rename from StringComparisonStringUnitTest/IndexOfUnitTest.cs rename to StringComparisonStringTestProject/IndexOfUnitTest.cs index 1b60ca3..eaa0705 100644 --- a/StringComparisonStringUnitTest/IndexOfUnitTest.cs +++ b/StringComparisonStringTestProject/IndexOfUnitTest.cs @@ -1,13 +1,11 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using JDanielSmith.System; +using JDanielSmith.System; namespace StringComparisonStringUnitTest; [TestClass] public class IndexOfUnitTest { - static readonly StringComparisonString abcABC = new("abcABC"); + static readonly StringComparisonString abcABC = new("abcABC"); [TestMethod] public void TestIndexOf() diff --git a/StringComparisonStringUnitTest/StringComparisonStringUnitTest.csproj b/StringComparisonStringTestProject/StringComparisonStringTestProject.csproj similarity index 58% rename from StringComparisonStringUnitTest/StringComparisonStringUnitTest.csproj rename to StringComparisonStringTestProject/StringComparisonStringTestProject.csproj index f5b6677..e6a55d3 100644 --- a/StringComparisonStringUnitTest/StringComparisonStringUnitTest.csproj +++ b/StringComparisonStringTestProject/StringComparisonStringTestProject.csproj @@ -1,17 +1,18 @@ - net6.0 - True + net7.0 + enable + enable false - - - - + + + + diff --git a/StringComparisonStringTestProject/Usings.cs b/StringComparisonStringTestProject/Usings.cs new file mode 100644 index 0000000..540383d --- /dev/null +++ b/StringComparisonStringTestProject/Usings.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; From f5ac489433c86e4a874f3f453558f9b2eab4b17b Mon Sep 17 00:00:00 2001 From: "J. Daniel Smith" Date: Tue, 19 Dec 2023 21:13:50 -0500 Subject: [PATCH 2/5] .NET 8.0; AOT --- StringComparisonString/StringComparison.cs | 16 ++++++++-------- .../StringComparisonString.csproj | 8 +++++--- .../StringComparisonStringTestProject.csproj | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/StringComparisonString/StringComparison.cs b/StringComparisonString/StringComparison.cs index 01673cd..780418b 100644 --- a/StringComparisonString/StringComparison.cs +++ b/StringComparisonString/StringComparison.cs @@ -1,4 +1,4 @@ -using SStringComparison = global::System.StringComparison; +using StringComparisonEnum = global::System.StringComparison; namespace JDanielSmith.System; @@ -9,7 +9,7 @@ public static class StringComparison /// public interface IStringComparison { - static abstract SStringComparison Comparison { get; } + static abstract StringComparisonEnum Comparison { get; } } /// @@ -17,7 +17,7 @@ public interface IStringComparison /// public struct CurrentCulture : IStringComparison { - public static SStringComparison Comparison { get; } = SStringComparison.CurrentCulture; + public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.CurrentCulture; } /// @@ -26,7 +26,7 @@ public struct CurrentCulture : IStringComparison /// public struct CurrentCultureIgnoreCase : IStringComparison { - public static SStringComparison Comparison { get; } = SStringComparison.CurrentCultureIgnoreCase; + public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.CurrentCultureIgnoreCase; } /// @@ -34,7 +34,7 @@ public struct CurrentCultureIgnoreCase : IStringComparison /// public struct InvariantCulture : IStringComparison { - public static SStringComparison Comparison { get; } = SStringComparison.InvariantCulture; + public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.InvariantCulture; } /// @@ -43,7 +43,7 @@ public struct InvariantCulture : IStringComparison /// public struct InvariantCultureIgnoreCase : IStringComparison { - public static SStringComparison Comparison { get; } = SStringComparison.InvariantCultureIgnoreCase; + public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.InvariantCultureIgnoreCase; } /// @@ -51,7 +51,7 @@ public struct InvariantCultureIgnoreCase : IStringComparison /// public struct Ordinal : IStringComparison { - public static SStringComparison Comparison { get; } = SStringComparison.Ordinal; + public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.Ordinal; } /// @@ -60,6 +60,6 @@ public struct Ordinal : IStringComparison /// public struct OrdinalIgnoreCase : IStringComparison { - public static SStringComparison Comparison { get; } = SStringComparison.OrdinalIgnoreCase; + public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.OrdinalIgnoreCase; } } \ No newline at end of file diff --git a/StringComparisonString/StringComparisonString.csproj b/StringComparisonString/StringComparisonString.csproj index cfadb03..6a4e4e9 100644 --- a/StringComparisonString/StringComparisonString.csproj +++ b/StringComparisonString/StringComparisonString.csproj @@ -1,9 +1,11 @@ - net7.0 - enable - enable + net8.0 + enable + enable + true + true diff --git a/StringComparisonStringTestProject/StringComparisonStringTestProject.csproj b/StringComparisonStringTestProject/StringComparisonStringTestProject.csproj index e6a55d3..8e7f9a6 100644 --- a/StringComparisonStringTestProject/StringComparisonStringTestProject.csproj +++ b/StringComparisonStringTestProject/StringComparisonStringTestProject.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable From df2a57b07b14bb0b42dd94769de9acdf5a58ccf2 Mon Sep 17 00:00:00 2001 From: "J. Daniel Smith" Date: Tue, 11 Feb 2025 17:00:59 +0100 Subject: [PATCH 3/5] dial-up code-analysis diagnostics --- .editorconfig | 11 ++ .github/workflows/codeql-analysis.yml | 71 ---------- StringComparisonString.sln | 5 + StringComparisonString/StringComparison.cs | 14 +- .../StringComparisonString.cs | 128 ++++++++++++------ .../StringComparisonString.csproj | 25 +++- .../StringComparisonString_IComparable.cs | 24 ++-- .../StringComparisonString_IEquatable.cs | 59 ++++++-- .../StringComparisonStringTestProject.csproj | 2 +- 9 files changed, 195 insertions(+), 144 deletions(-) create mode 100644 .editorconfig delete mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e15cb12 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +[*.cs] + +# IDE0160: Convert to block scoped namespace +csharp_style_namespace_declarations = file_scoped + +# IDE0040: Add accessibility modifiers +dotnet_style_require_accessibility_modifiers = omit_if_default + +# IDE0008: Use explicit type +csharp_style_var_elsewhere = true +dotnet_diagnostic.IDE0008.severity = none diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 2452dfe..0000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,71 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -name: "CodeQL" - -on: - push: - branches: [master] - pull_request: - # The branches below must be a subset of the branches above - branches: [master] - schedule: - - cron: '0 19 * * 0' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - # Override automatic language detection by changing the below list - # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['csharp'] - # Learn more... - # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/StringComparisonString.sln b/StringComparisonString.sln index 290529d..75e9683 100644 --- a/StringComparisonString.sln +++ b/StringComparisonString.sln @@ -7,6 +7,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StringComparisonString", "S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StringComparisonStringTestProject", "StringComparisonStringTestProject\StringComparisonStringTestProject.csproj", "{D7680924-FEC5-4A05-A0F6-571BE2A1B561}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A93E1766-AEA4-4E32-8E56-C0495BF41853}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/StringComparisonString/StringComparison.cs b/StringComparisonString/StringComparison.cs index 780418b..fe33681 100644 --- a/StringComparisonString/StringComparison.cs +++ b/StringComparisonString/StringComparison.cs @@ -1,6 +1,8 @@ using StringComparisonEnum = global::System.StringComparison; +#pragma warning disable IDE0130 // Namespace does not match folder structure namespace JDanielSmith.System; +#pragma warning restore IDE0130 // Namespace does not match folder structure public static class StringComparison { @@ -15,7 +17,7 @@ public interface IStringComparison /// /// Compare strings using culture-sensitive sort rules and the current culture. /// - public struct CurrentCulture : IStringComparison + public readonly struct CurrentCulture : IStringComparison { public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.CurrentCulture; } @@ -24,7 +26,7 @@ public struct CurrentCulture : IStringComparison /// Compare strings using culture-sensitive sort rules, the current culture, and /// ignoring the case of the strings being compared. /// - public struct CurrentCultureIgnoreCase : IStringComparison + public readonly struct CurrentCultureIgnoreCase : IStringComparison { public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.CurrentCultureIgnoreCase; } @@ -32,7 +34,7 @@ public struct CurrentCultureIgnoreCase : IStringComparison /// /// Compare strings using culture-sensitive sort rules and the invariant culture. /// - public struct InvariantCulture : IStringComparison + public readonly struct InvariantCulture : IStringComparison { public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.InvariantCulture; } @@ -41,7 +43,7 @@ public struct InvariantCulture : IStringComparison /// Compare strings using culture-sensitive sort rules, the invariant culture, and /// ignoring the case of the strings being compared. /// - public struct InvariantCultureIgnoreCase : IStringComparison + public readonly struct InvariantCultureIgnoreCase : IStringComparison { public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.InvariantCultureIgnoreCase; } @@ -49,7 +51,7 @@ public struct InvariantCultureIgnoreCase : IStringComparison /// /// Compare strings using ordinal sort rules. /// - public struct Ordinal : IStringComparison + public readonly struct Ordinal : IStringComparison { public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.Ordinal; } @@ -58,7 +60,7 @@ public struct Ordinal : IStringComparison /// Compare strings using ordinal sort rules and ignoring the case of the strings /// being compared. /// - public struct OrdinalIgnoreCase : IStringComparison + public readonly struct OrdinalIgnoreCase : IStringComparison { public static StringComparisonEnum Comparison { get; } = StringComparisonEnum.OrdinalIgnoreCase; } diff --git a/StringComparisonString/StringComparisonString.cs b/StringComparisonString/StringComparisonString.cs index c15d814..31110ad 100644 --- a/StringComparisonString/StringComparisonString.cs +++ b/StringComparisonString/StringComparisonString.cs @@ -1,8 +1,4 @@ -using System; - -#nullable enable - -namespace JDanielSmith.System; +namespace JDanielSmith.System; /// /// Provide a wrapper around System.String which automatically uses TStringComparison instead of having @@ -13,49 +9,105 @@ namespace JDanielSmith.System; /// /// Some hints from: http://stackoverflow.com/questions/33039324/how-can-system-string-be-properly-wrapped-for-case-insensitivy /// -public sealed partial class StringComparisonString : +public sealed partial class StringComparisonString(string value) : ICloneable, - IEquatable, IEquatable?>, + IEquatable, IEquatable?>, IComparable, IComparable, IComparable?> -where TStringComparison : StringComparison.IStringComparison +where TStringComparison : StringComparison.IStringComparison { static readonly global::System.StringComparison comparison_ = TStringComparison.Comparison; static readonly StringComparer comparer_ = StringComparer.FromComparison(comparison_); - public string Value { get; } - public StringComparisonString(string value) + public string Value { get; } = value ?? String.Empty; + + public override string ToString() { - Value = value ?? String.Empty; + return Value; } - public override string ToString() => Value; - public char this[int index] { get => Value[index]; } - public int Length { get => Value.Length; } + public char this[int index] => Value[index]; + public int Length => Value.Length; - public object Clone() => new StringComparisonString(Value); + public object Clone() + { + return new StringComparisonString(Value); + } // easily convert to/from System.String - public static implicit operator StringComparisonString(string source) => new(source); - public StringComparisonString FromString(string source) => new(source); - public static implicit operator string?(StringComparisonString? source) => source?.Value; - public bool Contains(String value) => Value.Contains(value, comparison_); - public bool Contains(char value) => Value.Contains(value, comparison_); - - - public bool EndsWith(string value) => Value.EndsWith(value, comparison_); - - public int IndexOf(string value) => Value.IndexOf(value, comparison_); - public int IndexOf(string value, int startIndex) => Value.IndexOf(value, startIndex, comparison_); - public int IndexOf(string value, int startIndex, int count) => Value.IndexOf(value, startIndex, count, comparison_); - public int IndexOf(char value) => Value.IndexOf(value, comparison_); - - public int LastIndexOf(string value) => Value.LastIndexOf(value, comparison_); - public int LastIndexOf(string value, int startIndex) => Value.LastIndexOf(value, startIndex, comparison_); - public int LastIndexOf(string value, int startIndex, int count) => Value.LastIndexOf(value, startIndex, count, comparison_); - - public string Replace(string oldValue, string? newValue) => Value.Replace(oldValue, newValue, comparison_); - - public bool StartsWith(string value) => Value.StartsWith(value, comparison_); + public static implicit operator StringComparisonString(string source) + { + return new(source); + } + + public StringComparisonString FromString(string source) + { + return new(source); + } + + public static implicit operator string?(StringComparisonString? source) + { + return source?.Value; + } + + public bool Contains(String value) + { + return Value.Contains(value, comparison_); + } + + public bool Contains(char value) + { + return Value.Contains(value, comparison_); + } + + public bool EndsWith(string value) + { + return Value.EndsWith(value, comparison_); + } + + public int IndexOf(string value) + { + return Value.IndexOf(value, comparison_); + } + + public int IndexOf(string value, int startIndex) + { + return Value.IndexOf(value, startIndex, comparison_); + } + + public int IndexOf(string value, int startIndex, int count) + { + return Value.IndexOf(value, startIndex, count, comparison_); + } + + public int IndexOf(char value) + { + return Value.IndexOf(value, comparison_); + } + + public int LastIndexOf(string value) + { + return Value.LastIndexOf(value, comparison_); + } + + public int LastIndexOf(string value, int startIndex) + { + return Value.LastIndexOf(value, startIndex, comparison_); + } + + public int LastIndexOf(string value, int startIndex, int count) + { + return Value.LastIndexOf(value, startIndex, count, comparison_); + } + + public string Replace(string oldValue, string? newValue) + { + return Value.Replace(oldValue, newValue, comparison_); + } + + public bool StartsWith(string value) + { + return Value.StartsWith(value, comparison_); + } } public static class StringComparisonString @@ -105,7 +157,7 @@ public static class StringComparisonString { return b is null; // Equals(null, null) == true } - return b is null ? false : a.Equals(b); + return b is not null && a.Equals(b); } public static bool Equals(StringComparisonString? a, string? b) where TStringComparison : StringComparison.IStringComparison, new() { @@ -113,7 +165,7 @@ public static class StringComparisonString { return b is null; // Equals(null, null) == true } - return b is null ? false : a.Equals(b); + return b is not null && a.Equals(b); } public static bool Equals(string? a, StringComparisonString? b) where TStringComparison : StringComparison.IStringComparison, new() { diff --git a/StringComparisonString/StringComparisonString.csproj b/StringComparisonString/StringComparisonString.csproj index 6a4e4e9..54adfaa 100644 --- a/StringComparisonString/StringComparisonString.csproj +++ b/StringComparisonString/StringComparisonString.csproj @@ -1,11 +1,32 @@ - + - net8.0 + net9.0 enable enable true true + README.md + https://github.com/JDanielSmith/StringComparisonString + https://github.com/JDanielSmith/StringComparisonString + preview-all + + 9999 + True + + + + 9999 + True + + + + + True + \ + + + diff --git a/StringComparisonString/StringComparisonString_IComparable.cs b/StringComparisonString/StringComparisonString_IComparable.cs index be05897..0af2249 100644 --- a/StringComparisonString/StringComparisonString_IComparable.cs +++ b/StringComparisonString/StringComparisonString_IComparable.cs @@ -1,8 +1,4 @@ -using System; - -#nullable enable - -namespace JDanielSmith.System; +namespace JDanielSmith.System; /// /// Provide a wrapper around System.String which automatically uses TStringComparison instead of having @@ -19,18 +15,14 @@ public int CompareTo(object? obj) { // https://msdn.microsoft.com/en-us/library/4d7sx9hd(v=vs.110).aspx if (obj is null) + { return 1; // If other is not a valid object reference, this instance is greater. + } // obj must be either StringOrdinalIgnoreCase or String - var other = obj as StringComparisonString; - if (other is null) + if (obj is not StringComparisonString other) { - var s_other = obj as string; - if (s_other is null) -#pragma warning disable CA1303 // Do not pass literals as localized parameters - throw new ArgumentException("Object must be of type " + nameof(StringComparisonString) + " or String."); -#pragma warning restore CA1303 // Do not pass literals as localized parameters - + var s_other = obj as string ?? throw new ArgumentException("Object must be of type " + nameof(StringComparisonString) + " or String."); return CompareTo(s_other); // call CompareTo(string) } @@ -40,10 +32,14 @@ public int CompareTo(StringComparisonString? other) { // https://msdn.microsoft.com/en-us/library/4d7sx9hd(v=vs.110).aspx if (other is null) + { return 1; // If other is not a valid object reference, this instance is greater. + } if (ReferenceEquals(Value, other.Value)) + { return 0; + } return CompareTo(other.Value); // call CompareTo(string) } @@ -51,7 +47,9 @@ public int CompareTo(string? other) { // https://msdn.microsoft.com/en-us/library/4d7sx9hd(v=vs.110).aspx if (other is null) + { return 1; // If other is not a valid object reference, this instance is greater. + } return comparer_.Compare(Value, other); } diff --git a/StringComparisonString/StringComparisonString_IEquatable.cs b/StringComparisonString/StringComparisonString_IEquatable.cs index 55dac53..7703112 100644 --- a/StringComparisonString/StringComparisonString_IEquatable.cs +++ b/StringComparisonString/StringComparisonString_IEquatable.cs @@ -1,8 +1,4 @@ -using System; - -#nullable enable - -namespace JDanielSmith.System; +namespace JDanielSmith.System; /// /// Provide a wrapper around System.String which automatically uses TStringComparison instead of having @@ -18,42 +14,79 @@ public sealed partial class StringComparisonString public override bool Equals(object? obj) { if (obj is null) + { return false; // this != null + } var other = obj as StringComparisonString; if (other is not null) + { return Equals(other); // call Equals(StringComparisonString) + } var s_other = obj as string; if (s_other is not null) + { return Equals(s_other); // call Equals(string) + } return comparer_.Equals(obj); } public bool Equals(StringComparisonString? other) { if (other is null) + { return false; // this != null + } + return Equals(other.Value); // call Equals(string) } - public bool Equals(string? other) => comparer_.Equals(Value, other); - public override int GetHashCode() => comparer_.GetHashCode(Value); + public bool Equals(string? other) + { + return comparer_.Equals(Value, other); + } + + public override int GetHashCode() + { + return comparer_.GetHashCode(Value); + } public static bool operator ==(StringComparisonString x, StringComparisonString y) { if (x is null) - return (y is null); // null == null, null != something + { + return y is null; // null == null, null != something + } + return x.Equals(y); // know x != null } public static bool operator ==(StringComparisonString x, string y) { if (x is null) - return (y is null); // null == null, null != something + { + return y is null; // null == null, null != something + } + return x.Equals(y); // know x != null } - public static bool operator ==(string x, StringComparisonString y) => y == x; // == is commutative, x == y - public static bool operator !=(StringComparisonString x, StringComparisonString y) => !(x == y); - public static bool operator !=(string x, StringComparisonString y) => !(x == y); - public static bool operator !=(StringComparisonString x, string y) => !(x == y); + public static bool operator ==(string x, StringComparisonString y) + { + return y == x; // == is commutative, x == y + } + + public static bool operator !=(StringComparisonString x, StringComparisonString y) + { + return !(x == y); + } + + public static bool operator !=(string x, StringComparisonString y) + { + return !(x == y); + } + + public static bool operator !=(StringComparisonString x, string y) + { + return !(x == y); + } } diff --git a/StringComparisonStringTestProject/StringComparisonStringTestProject.csproj b/StringComparisonStringTestProject/StringComparisonStringTestProject.csproj index 8e7f9a6..b287e50 100644 --- a/StringComparisonStringTestProject/StringComparisonStringTestProject.csproj +++ b/StringComparisonStringTestProject/StringComparisonStringTestProject.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable From 79446b7ba0dae96d87bc4cd267cb351a5e3a2676 Mon Sep 17 00:00:00 2001 From: "J. Daniel Smith" Date: Sat, 22 Nov 2025 11:49:51 +0100 Subject: [PATCH 4/5] Add CodeQL analysis workflow configuration --- .github/workflows/codeql.yml | 99 ++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..3f76a53 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,99 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '26 14 * * 5' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: csharp + build-mode: none + # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Add any setup steps before running the `github/codeql-action/init` action. + # This includes steps like installing compilers or runtimes (`actions/setup-node` + # or others). This is typically only required for manual builds. + # - name: Setup runtime (example) + # uses: actions/setup-example@v1 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - name: Run manual build steps + if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{matrix.language}}" From ea2a0acf95a84c8fc55251e4bca5d6583a971d1b Mon Sep 17 00:00:00 2001 From: "J. Daniel Smith" Date: Sat, 22 Nov 2025 12:03:05 +0100 Subject: [PATCH 5/5] Remove CodeQL analysis workflow configuration --- .github/workflows/codeql.yml | 99 ------------------------------------ 1 file changed, 99 deletions(-) delete mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 3f76a53..0000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,99 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL Advanced" - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - schedule: - - cron: '26 14 * * 5' - -jobs: - analyze: - name: Analyze (${{ matrix.language }}) - # Runner size impacts CodeQL analysis time. To learn more, please see: - # - https://gh.io/recommended-hardware-resources-for-running-codeql - # - https://gh.io/supported-runners-and-hardware-resources - # - https://gh.io/using-larger-runners (GitHub.com only) - # Consider using larger runners or machines with greater resources for possible analysis time improvements. - runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} - permissions: - # required for all workflows - security-events: write - - # required to fetch internal or private CodeQL packs - packages: read - - # only required for workflows in private repositories - actions: read - contents: read - - strategy: - fail-fast: false - matrix: - include: - - language: csharp - build-mode: none - # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift' - # Use `c-cpp` to analyze code written in C, C++ or both - # Use 'java-kotlin' to analyze code written in Java, Kotlin or both - # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both - # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, - # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. - # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how - # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Add any setup steps before running the `github/codeql-action/init` action. - # This includes steps like installing compilers or runtimes (`actions/setup-node` - # or others). This is typically only required for manual builds. - # - name: Setup runtime (example) - # uses: actions/setup-example@v1 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v4 - with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - # If the analyze step fails for one of the languages you are analyzing with - # "We were unable to automatically build your code", modify the matrix above - # to set the build mode to "manual" for that language. Then modify this step - # to build your code. - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - name: Run manual build steps - if: matrix.build-mode == 'manual' - shell: bash - run: | - echo 'If you are using a "manual" build mode for one or more of the' \ - 'languages you are analyzing, replace this with the commands to build' \ - 'your code, for example:' - echo ' make bootstrap' - echo ' make release' - exit 1 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 - with: - category: "/language:${{matrix.language}}"