diff --git a/.editorconfig b/.editorconfig
index 6edce03..cb61c33 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -56,20 +56,20 @@ csharp_preserve_single_line_statements=true
#Style - Code block preferences
#prefer no curly braces if allowed
-csharp_prefer_braces=false:suggestion
+csharp_prefer_braces= false:suggestion
#Style - expression bodied member options
#prefer expression-bodied members for accessors
-csharp_style_expression_bodied_accessors=true:suggestion
+csharp_style_expression_bodied_accessors= true:suggestion
#prefer block bodies for constructors
-csharp_style_expression_bodied_constructors=false:suggestion
+csharp_style_expression_bodied_constructors= false:suggestion
#prefer expression-bodied members for indexers
-csharp_style_expression_bodied_indexers=true:suggestion
+csharp_style_expression_bodied_indexers= true:suggestion
#prefer block bodies for methods
-csharp_style_expression_bodied_methods=when_on_single_line
+csharp_style_expression_bodied_methods= when_on_single_line:silent
#prefer expression-bodied members for properties
-csharp_style_expression_bodied_properties=true:suggestion
+csharp_style_expression_bodied_properties= true:suggestion
#Style - expression level options
@@ -79,7 +79,7 @@ dotnet_style_predefined_type_for_member_access=true:suggestion
#Style - Expression-level preferences
#prefer default(T) over default
-csharp_prefer_simple_default_expression=false:suggestion
+csharp_prefer_simple_default_expression= false:suggestion
#Style - implicit and explicit types
@@ -130,3 +130,129 @@ dotnet_remove_unnecessary_suppression_exclusions=category: ReSharper
# ReSharper properties
resharper_space_within_single_line_array_initializer_braces=true
+
+[*.cs]
+#### Naming styles ####
+
+# Naming rules
+
+dotnet_naming_rule.async_method_should_be_pascal_case_async.severity = warning
+dotnet_naming_rule.async_method_should_be_pascal_case_async.symbols = async_method
+dotnet_naming_rule.async_method_should_be_pascal_case_async.style = pascal_case_async
+
+dotnet_naming_rule.method_should_be_pascal_case.severity = warning
+dotnet_naming_rule.method_should_be_pascal_case.symbols = method
+dotnet_naming_rule.method_should_be_pascal_case.style = pascal_case
+
+# Symbol specifications
+
+dotnet_naming_symbols.async_method.applicable_kinds = method
+dotnet_naming_symbols.async_method.applicable_accessibilities = *
+dotnet_naming_symbols.async_method.required_modifiers = async
+
+dotnet_naming_symbols.method.applicable_kinds = method
+dotnet_naming_symbols.method.applicable_accessibilities = public
+dotnet_naming_symbols.method.required_modifiers =
+
+# Naming styles
+
+dotnet_naming_style.pascal_case_async.required_prefix =
+dotnet_naming_style.pascal_case_async.required_suffix = Async
+dotnet_naming_style.pascal_case_async.word_separator =
+dotnet_naming_style.pascal_case_async.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+csharp_using_directive_placement = outside_namespace:silent
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_style_namespace_declarations = block_scoped:silent
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_style_prefer_primary_constructors = false:suggestion
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = false:silent
+csharp_style_throw_expression = true:suggestion
+csharp_style_prefer_null_check_over_type_check = true:suggestion
+csharp_style_prefer_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
+csharp_style_prefer_tuple_swap = true:suggestion
+csharp_style_prefer_utf8_string_literals = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+csharp_indent_labels = one_less_than_current
+csharp_space_around_binary_operators = before_and_after
+
+[*.{cs,vb}]
+#### Naming styles ####
+
+# Naming rules
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# Symbol specifications
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# Naming styles
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion
+dotnet_style_namespace_match_folder = true:suggestion
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+tab_width = 4
+indent_size = 4
+end_of_line = crlf
diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml
new file mode 100644
index 0000000..bfaa243
--- /dev/null
+++ b/.github/workflows/build-publish.yml
@@ -0,0 +1,92 @@
+name: Build and Publish
+on: [push, workflow_dispatch]
+
+env:
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
+ DOTNET_NOLOGO: true
+ NUGET_DIR: ${{ github.workspace }}/nuget
+
+jobs:
+ unit_tests:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup .Net
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.x
+ cache: true
+ cache-dependency-path: '**/packages.lock.json'
+
+ - name: Restore Nuget Packages
+ run: dotnet restore --locked-mode
+
+ - name: Clean Debug
+ run: dotnet clean --configuration Debug
+
+ - name: Build Debug
+ run: dotnet build --configuration Debug --no-restore --packages ./.nuget/packages
+
+ - name: Unit Tests
+ run: dotnet test --configuration Debug --no-build --filter TestCategory=Unit
+
+ build_publish:
+ if: ${{ startsWith(github.ref_name, 'prerelease') || startsWith(github.ref_name, 'release') }}
+ runs-on: ubuntu-latest
+ needs: [unit_tests]
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup .Net
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.x
+ cache: true
+ cache-dependency-path: '**/packages.lock.json'
+
+ - name: Setup Environment Variables
+ run: |
+ github_sha_hash=${{ github.sha }}
+
+ git_hash="${github_sha_hash:0:7}"
+
+ TZ=America/Denver
+
+ printf -v jdate '%(%y%j%H%M)T'
+
+ branch_name=${{github.ref_name}}
+
+ values=(${branch_name//_/ })
+
+ branch=${values[0]}
+ version=${values[1]}
+
+ if [ $branch == 'release' ]; then
+ branch_version="${version}+${git_hash}"
+ elif [ $branch == 'dev' ]; then
+ branch_version="9.0.0-pre.${jdate}+${git_hash}"
+ else
+ branch_version="${version}-pre.${jdate}+${git_hash}"
+ fi
+
+ echo $branch_version
+
+ echo "BRANCH_VERSION=${branch_version}" >> "$GITHUB_ENV"
+
+ - name: Restore Nuget Packages
+ run: dotnet restore --locked-mode
+
+ - name: Clean Release
+ run: dotnet clean --configuration Release
+
+ - name: Build Release
+ run: dotnet build --configuration Release --no-restore -p:Version="$BRANCH_VERSION" -p:PublishRepositoryUrl=true
+
+ - name: Package Nuget
+ run: dotnet pack --configuration Release --no-build --include-symbols -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg -p:PackageVersion="$BRANCH_VERSION" --output "$NUGET_DIR"
+
+ - name: Publish Nuget
+ env:
+ NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
+ run: dotnet nuget push "$NUGET_DIR\*.nupkg" -k "$NUGET_API_KEY"
diff --git a/Jenkinsfile b/Jenkinsfile.old
similarity index 100%
rename from Jenkinsfile
rename to Jenkinsfile.old
diff --git a/STR.Common.sln b/STR.Common.sln
index 29d7604..838c6de 100644
--- a/STR.Common.sln
+++ b/STR.Common.sln
@@ -1,21 +1,28 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.28803.156
+# Visual Studio Version 17
+VisualStudioVersion = 17.13.35828.75
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Str.Common", "Str.Common\Str.Common.csproj", "{5E07704B-4938-4D5F-A695-F87E016AC7BF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A51EE79F-F52E-4DDD-9FBB-F0A5BE4EC2DE}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
- Jenkinsfile = Jenkinsfile
LICENSE = LICENSE
+ Jenkinsfile.old = Jenkinsfile.old
ReadMe.md = ReadMe.md
STR.Common.sln.DotSettings = STR.Common.sln.DotSettings
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Str.Common.Tests", "Str.Common.Tests\Str.Common.Tests.csproj", "{4FB30997-A73F-485F-BC45-62B6D3B8944C}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{9E962354-5E96-438D-B5CE-E6BFD20D2152}"
+ ProjectSection(SolutionItems) = preProject
+ .github\workflows\build-publish.yml = .github\workflows\build-publish.yml
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -34,6 +41,10 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {A51EE79F-F52E-4DDD-9FBB-F0A5BE4EC2DE}
+ {9E962354-5E96-438D-B5CE-E6BFD20D2152} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0157AB65-53CD-4464-B113-6D50BE77B2FA}
EndGlobalSection
diff --git a/STR.Common.sln.DotSettings b/STR.Common.sln.DotSettings
index ef24329..748361e 100644
--- a/STR.Common.sln.DotSettings
+++ b/STR.Common.sln.DotSettings
@@ -52,8 +52,12 @@
UseExplicitType
<Policy Inspect="False" Prefix="" Suffix="" Style="aaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy>
+ <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Parameters"><ElementKinds><Kind Name="PARAMETER" /></ElementKinds></Descriptor><Policy Inspect="False" Prefix="" Suffix="" Style="aaBb" /></Policy>
+ <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy>
BOTH_SIDES
True
True
True
- True
\ No newline at end of file
+ True
+ True
\ No newline at end of file
diff --git a/Str.Common.Tests/LockingObservableCollectionTests.cs b/Str.Common.Tests/LockingObservableCollectionTests.cs
index 2ea318c..72594d9 100644
--- a/Str.Common.Tests/LockingObservableCollectionTests.cs
+++ b/Str.Common.Tests/LockingObservableCollectionTests.cs
@@ -11,156 +11,156 @@ namespace Str.Common.Tests;
[TestClass]
public class LockingObservableCollectionTests {
- #region OnCollectionChanged Tests
+ #region OnCollectionChanged Tests
- [TestMethod, TestCategory("Unit")]
- public void OnCollectionChangedAddEventTest() {
- TestClass tester = new();
+ [TestMethod, TestCategory("Unit")]
+ public void OnCollectionChangedAddEventTest() {
+ TestClass tester = new();
- LockingObservableCollection testCollection = [];
+ LockingObservableCollection testCollection = [];
- int changedCount = 0;
+ int changedCount = 0;
- testCollection.CollectionChanged += (_, args) => {
- if (args.Action == NotifyCollectionChangedAction.Add) ++changedCount;
- };
+ testCollection.CollectionChanged += (_, args) => {
+ if (args.Action == NotifyCollectionChangedAction.Add) ++changedCount;
+ };
- testCollection.Add(tester);
+ testCollection.Add(tester);
- Assert.AreEqual(1, changedCount);
- }
+ Assert.AreEqual(1, changedCount);
+ }
- [TestMethod, TestCategory("Unit")]
- public void OnCollectionChangedRemoveEventTest() {
- TestClass tester1 = new();
- TestClass tester2 = new();
+ [TestMethod, TestCategory("Unit")]
+ public void OnCollectionChangedRemoveEventTest() {
+ TestClass tester1 = new();
+ TestClass tester2 = new();
- LockingObservableCollection testCollection = [];
+ LockingObservableCollection testCollection = [];
- int changedCount = 0;
+ int changedCount = 0;
- testCollection.CollectionChanged += (_, args) => {
- if (args.Action == NotifyCollectionChangedAction.Remove) ++changedCount;
- };
+ testCollection.CollectionChanged += (_, args) => {
+ if (args.Action == NotifyCollectionChangedAction.Remove) ++changedCount;
+ };
- testCollection.Add(tester1);
- testCollection.Add(tester2);
+ testCollection.Add(tester1);
+ testCollection.Add(tester2);
- testCollection.Remove(tester1);
+ testCollection.Remove(tester1);
- Assert.AreEqual(1, changedCount);
- }
+ Assert.AreEqual(1, changedCount);
+ }
- [TestMethod, TestCategory("Unit")]
- public void OnCollectionChangedResetEventTest() {
- TestClass tester1 = new();
- TestClass tester2 = new();
+ [TestMethod, TestCategory("Unit")]
+ public void OnCollectionChangedResetEventTest() {
+ TestClass tester1 = new();
+ TestClass tester2 = new();
- LockingObservableCollection testCollection = [];
+ LockingObservableCollection testCollection = [];
- int changedCount = 0;
+ int changedCount = 0;
- testCollection.CollectionChanged += (_, args) => {
- if (args.Action == NotifyCollectionChangedAction.Reset) ++changedCount;
- };
+ testCollection.CollectionChanged += (_, args) => {
+ if (args.Action == NotifyCollectionChangedAction.Reset) ++changedCount;
+ };
- testCollection.Add(tester1);
- testCollection.Add(tester2);
+ testCollection.Add(tester1);
+ testCollection.Add(tester2);
- testCollection.Clear();
+ testCollection.Clear();
- Assert.AreEqual(1, changedCount);
- }
+ Assert.AreEqual(1, changedCount);
+ }
- [TestMethod, TestCategory("Unit")]
- public void OnCollectionChangedReplaceEventTest() {
- TestClass tester1 = new();
- TestClass tester2 = new();
+ [TestMethod, TestCategory("Unit")]
+ public void OnCollectionChangedReplaceEventTest() {
+ TestClass tester1 = new();
+ TestClass tester2 = new();
- LockingObservableCollection testCollection = [];
+ LockingObservableCollection testCollection = [];
- int changedCount = 0;
+ int changedCount = 0;
- testCollection.CollectionChanged += (_, args) => {
- if (args.Action == NotifyCollectionChangedAction.Replace) ++changedCount;
- };
+ testCollection.CollectionChanged += (_, args) => {
+ if (args.Action == NotifyCollectionChangedAction.Replace) ++changedCount;
+ };
- testCollection.Add(tester1);
+ testCollection.Add(tester1);
- testCollection[0] = tester2;
+ testCollection[0] = tester2;
- Assert.AreEqual(1, changedCount);
- }
+ Assert.AreEqual(1, changedCount);
+ }
- [TestMethod, TestCategory("Unit")]
- public void OnCollectionChangedMoveEventTest() {
- TestClass tester1 = new();
- TestClass tester2 = new();
+ [TestMethod, TestCategory("Unit")]
+ public void OnCollectionChangedMoveEventTest() {
+ TestClass tester1 = new();
+ TestClass tester2 = new();
- LockingObservableCollection testCollection = [];
+ LockingObservableCollection testCollection = [];
- int changedCount = 0;
+ int changedCount = 0;
- testCollection.CollectionChanged += (_, args) => {
- if (args.Action == NotifyCollectionChangedAction.Move) ++changedCount;
- };
+ testCollection.CollectionChanged += (_, args) => {
+ if (args.Action == NotifyCollectionChangedAction.Move) ++changedCount;
+ };
- testCollection.Add(tester1);
- testCollection.Add(tester2);
+ testCollection.Add(tester1);
+ testCollection.Add(tester2);
- testCollection.Move(0, 1);
+ testCollection.Move(0, 1);
- Assert.AreEqual(1, changedCount);
- }
+ Assert.AreEqual(1, changedCount);
+ }
- [TestMethod, TestCategory("Unit")]
- public void OnCollectionChangedMoveEventSameIndexTest() {
- TestClass tester1 = new();
- TestClass tester2 = new();
+ [TestMethod, TestCategory("Unit")]
+ public void OnCollectionChangedMoveEventSameIndexTest() {
+ TestClass tester1 = new();
+ TestClass tester2 = new();
- LockingObservableCollection testCollection = [];
+ LockingObservableCollection testCollection = [];
- int changedCount = 0;
+ int changedCount = 0;
- testCollection.CollectionChanged += (_, args) => {
- if (args.Action == NotifyCollectionChangedAction.Move) ++changedCount;
- };
+ testCollection.CollectionChanged += (_, args) => {
+ if (args.Action == NotifyCollectionChangedAction.Move) ++changedCount;
+ };
- testCollection.Add(tester1);
- testCollection.Add(tester2);
+ testCollection.Add(tester1);
+ testCollection.Add(tester2);
- testCollection.Move(1, 1);
+ testCollection.Move(1, 1);
- Assert.AreEqual(0, changedCount);
- }
+ Assert.AreEqual(0, changedCount);
+ }
- [TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException)), TestCategory("Unit")]
- public void OnCollectionChangedMoveSourceOutOfRangeTest() {
- TestClass tester1 = new();
- TestClass tester2 = new();
+ [TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException)), TestCategory("Unit")]
+ public void OnCollectionChangedMoveSourceOutOfRangeTest() {
+ TestClass tester1 = new();
+ TestClass tester2 = new();
- LockingObservableCollection testCollection = [ tester1, tester2 ];
+ LockingObservableCollection testCollection = [tester1, tester2];
- testCollection.Move(2, 1);
- }
+ testCollection.Move(2, 1);
+ }
- [TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException)), TestCategory("Unit")]
- public void OnCollectionChangedMoveDestinationOutOfRangeTest() {
- TestClass tester1 = new();
- TestClass tester2 = new();
+ [TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException)), TestCategory("Unit")]
+ public void OnCollectionChangedMoveDestinationOutOfRangeTest() {
+ TestClass tester1 = new();
+ TestClass tester2 = new();
- LockingObservableCollection testCollection = [ tester1, tester2 ];
+ LockingObservableCollection testCollection = [tester1, tester2];
- testCollection.Move(1, 2);
- }
+ testCollection.Move(1, 2);
+ }
- #endregion OnCollectionChanged Tests
+ #endregion OnCollectionChanged Tests
- #region Private Class
+ #region Private Class
- private class TestClass;
+ private class TestClass;
- #endregion Private Class
+ #endregion Private Class
}
diff --git a/Str.Common.Tests/LockingReadOnlyCollectionTests.cs b/Str.Common.Tests/LockingReadOnlyCollectionTests.cs
index 5275cbb..f770ee2 100644
--- a/Str.Common.Tests/LockingReadOnlyCollectionTests.cs
+++ b/Str.Common.Tests/LockingReadOnlyCollectionTests.cs
@@ -4,14 +4,14 @@
using Str.Common.Extensions;
-namespace Str.Common.Tests;
+namespace Str.Common.Tests;
[TestClass]
public class LockingReadOnlyCollectionTests {
[TestMethod, TestCategory("Unit")]
public void LockingReadOnlyCollectionCount() {
- List source = new() { 1, 2, 3 };
+ List source = [1, 2, 3];
LockingReadOnlyCollection tester = source.ToLockingReadOnlyCollection();
@@ -20,7 +20,7 @@ public void LockingReadOnlyCollectionCount() {
[TestMethod, TestCategory("Unit")]
public void LockingReadOnlyCollectionContains() {
- List source = new() { 1, 2, 3 };
+ List source = [1, 2, 3];
LockingReadOnlyCollection tester = source.ToLockingReadOnlyCollection();
@@ -29,7 +29,7 @@ public void LockingReadOnlyCollectionContains() {
[TestMethod, TestCategory("Unit")]
public void LockingReadOnlyCollectionCopyTo() {
- List source = new() { 1, 2, 3 };
+ List source = [1, 2, 3];
LockingReadOnlyCollection tester = source.ToLockingReadOnlyCollection();
@@ -44,7 +44,7 @@ public void LockingReadOnlyCollectionCopyTo() {
[TestMethod, TestCategory("Unit")]
public void LockingReadOnlyCollectionIsReadOnly() {
- List source = new() { 1, 2, 3 };
+ List source = [1, 2, 3];
LockingReadOnlyCollection tester = source.ToLockingReadOnlyCollection();
@@ -53,7 +53,7 @@ public void LockingReadOnlyCollectionIsReadOnly() {
[TestMethod, TestCategory("Unit")]
public void LockingReadOnlyCollectionIsEnumerable() {
- List source = new() { 1, 2, 3 };
+ List source = [1, 2, 3];
LockingReadOnlyCollection tester = source.ToLockingReadOnlyCollection();
@@ -64,7 +64,7 @@ public void LockingReadOnlyCollectionIsEnumerable() {
[TestMethod, TestCategory("Unit")]
public void LockingReadOnlyCollectionIndexOf() {
- List source = new() { 1, 2, 3 };
+ List source = [1, 2, 3];
LockingReadOnlyCollection tester = source.ToLockingReadOnlyCollection();
@@ -75,7 +75,7 @@ public void LockingReadOnlyCollectionIndexOf() {
[TestMethod, TestCategory("Unit")]
public void LockingReadOnlyCollectionIndexer() {
- List source = new() { 1, 2, 3 };
+ List source = [1, 2, 3];
LockingReadOnlyCollection tester = source.ToLockingReadOnlyCollection();
diff --git a/Str.Common.Tests/Str.Common.Tests.csproj b/Str.Common.Tests/Str.Common.Tests.csproj
index 6c8df6d..1ada754 100644
--- a/Str.Common.Tests/Str.Common.Tests.csproj
+++ b/Str.Common.Tests/Str.Common.Tests.csproj
@@ -1,12 +1,13 @@
- net8.0
+ net9.0
false
true
enable
+ true
@@ -15,10 +16,10 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Str.Common.Tests/TaskExtensionTests.cs b/Str.Common.Tests/TaskExtensionTests.cs
index b376a7d..97378b5 100644
--- a/Str.Common.Tests/TaskExtensionTests.cs
+++ b/Str.Common.Tests/TaskExtensionTests.cs
@@ -3,62 +3,65 @@
using Str.Common.Extensions;
-namespace Str.Common.Tests;
+namespace Str.Common.Tests;
[TestClass]
public class TaskExtensionTests {
- #region FireAndForget Tests
+ #region FireAndForget Tests
- [TestMethod, TestCategory("Unit")]
- public void FireAndForgetTaskNoActionSuccess() {
- MethodAsync().FireAndForget();
- }
+ [TestMethod, TestCategory("Unit")]
+ public void FireAndForgetTaskNoActionSuccess() {
+ MethodAsync().FireAndForget();
+ }
- [TestMethod, TestCategory("Unit")]
- public void FireAndForgetTaskNoActionException()
- {
- MethodAsync(true).FireAndForget(); // Exception is dropped on the floor
- }
+ [TestMethod, TestCategory("Unit")]
+ public void FireAndForgetTaskNoActionException() {
+ MethodAsync(true).FireAndForget(); // Exception is dropped on the floor
+ }
- [TestMethod, TestCategory("Unit")]
- public async Task FireAndForgetTaskActionSuccess() {
- int callbackCount = 0;
+ [TestMethod, TestCategory("Unit")]
+ public async Task FireAndForgetTaskActionSuccessAsync() {
+ int callbackCount = 0;
- void callback(Exception ex) { ++callbackCount; }
+ MethodAsync().FireAndForget(Callback);
- MethodAsync().FireAndForget(callback);
+ await Task.Delay(1000).Fire();
- await Task.Delay(1000).Fire();
+ Assert.AreEqual(0, callbackCount);
- Assert.AreEqual(0, callbackCount);
- }
+ return;
- [TestMethod, TestCategory("Unit")]
- public async Task FireAndForgetTaskActionException() {
- int callbackCount = 0;
+ void Callback(Exception ex) { ++callbackCount; }
+ }
- void callback(Exception ex) { ++callbackCount; }
+ [TestMethod, TestCategory("Unit")]
+ public async Task FireAndForgetTaskActionExceptionAsync() {
+ int callbackCount = 0;
- MethodAsync(true).FireAndForget(callback);
+ MethodAsync(true).FireAndForget(Callback);
- await Task.Delay(1000).Fire();
+ await Task.Delay(1000).Fire();
- Assert.AreEqual(1, callbackCount);
- }
+ Assert.AreEqual(1, callbackCount);
- #endregion FireAndForget Tests
+ return;
- #region Private Methods
+ void Callback(Exception ex) { ++callbackCount; }
+ }
- private static async Task MethodAsync(bool throwException = false) {
- await Task.Delay(500).ConfigureAwait(false);
+ #endregion FireAndForget Tests
- if (throwException) throw new Exception();
+ #region Private Methods
- await Task.CompletedTask.ConfigureAwait(false);
- }
+ private static async Task MethodAsync(bool throwException = false) {
+ await Task.Delay(500).ConfigureAwait(false);
- #endregion Private Methods
+ if (throwException) throw new Exception();
-}
\ No newline at end of file
+ await Task.CompletedTask.ConfigureAwait(false);
+ }
+
+ #endregion Private Methods
+
+}
diff --git a/Str.Common.Tests/TraverseTests.cs b/Str.Common.Tests/TraverseTests.cs
index 1c89782..18a391f 100644
--- a/Str.Common.Tests/TraverseTests.cs
+++ b/Str.Common.Tests/TraverseTests.cs
@@ -7,7 +7,8 @@
using Str.Common.Extensions;
-namespace Str.Common.Tests;
+namespace Str.Common.Tests;
+
[TestClass]
public class TraverseTests {
@@ -22,7 +23,7 @@ public class TraverseTests {
[ClassInitialize]
public static void ClassInit(TestContext _) {
- root = new LockingObservableCollection();
+ root = [];
TestClass branch1 = new() { Value = 1 };
TestClass branch2 = new() { Value = 2 };
@@ -68,7 +69,7 @@ public void TraverseTestWithPredicate() {
[TestMethod, TestCategory("Unit")]
[SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")]
public void TraverseTestEmptyTreeNoPredicate() {
- LockingObservableCollection test = new();
+ LockingObservableCollection test = [];
IEnumerable flat = test.Traverse();
@@ -80,7 +81,7 @@ public void TraverseTestEmptyTreeNoPredicate() {
[TestMethod, TestCategory("Unit")]
[SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")]
public void TraverseTestEmptyTreeWithPredicate() {
- LockingObservableCollection test = new();
+ LockingObservableCollection test = [];
IEnumerable flat = test.Traverse(tc => tc.Value == 1);
@@ -93,12 +94,13 @@ public void TraverseTestEmptyTreeWithPredicate() {
}
+
public class TestClass : ITraversable {
- public int Value { get; set; }
+ public int Value { get; init; }
- public LockingObservableCollection Children { get; } = new();
+ public LockingObservableCollection Children { get; } = [];
IEnumerable ITraversable.Children => Children;
-}
\ No newline at end of file
+}
diff --git a/Str.Common.Tests/packages.lock.json b/Str.Common.Tests/packages.lock.json
new file mode 100644
index 0000000..8986c51
--- /dev/null
+++ b/Str.Common.Tests/packages.lock.json
@@ -0,0 +1,157 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net9.0": {
+ "AsyncFixer": {
+ "type": "Direct",
+ "requested": "[1.6.0, )",
+ "resolved": "1.6.0",
+ "contentHash": "/Xfs9H3UMfEv64cwT+C/JrTRp4w08BmPuFbj0ageadCHpx6rxYJxAU2C6sEqRFG22xmGk5cX9ewzoiiehWVHOw=="
+ },
+ "ConfigureAwaitEnforcer": {
+ "type": "Direct",
+ "requested": "[2.0.0, )",
+ "resolved": "2.0.0",
+ "contentHash": "jkoGjQWaD5ioGPCv/Oi/tsCEcGWfLgOHeN9IPrZbzS8epgbuBQREFlg0Oe7J6yRZuhxMyfJrSmdXtnhNgdmkLw=="
+ },
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.13.0, )",
+ "resolved": "17.13.0",
+ "contentHash": "W19wCPizaIC9Zh47w8wWI/yxuqR7/dtABwOrc8r2jX/8mUNxM2vw4fXDh+DJTeogxV+KzKwg5jNNGQVwf3LXyA==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.13.0",
+ "Microsoft.TestPlatform.TestHost": "17.13.0"
+ }
+ },
+ "MSTest.TestAdapter": {
+ "type": "Direct",
+ "requested": "[3.8.2, )",
+ "resolved": "3.8.2",
+ "contentHash": "Xzch3LrRJKzIMP6D956W0DEy8NInkNSXS9novzEC72hMz8VlhDamRNDsR+b5QMvct+1TTIWRvw6cBHtiMB6Ajw==",
+ "dependencies": {
+ "Microsoft.Testing.Extensions.VSTestBridge": "1.6.2",
+ "Microsoft.Testing.Platform.MSBuild": "1.6.2"
+ }
+ },
+ "MSTest.TestFramework": {
+ "type": "Direct",
+ "requested": "[3.8.2, )",
+ "resolved": "3.8.2",
+ "contentHash": "GE6TAA3yC6rYFZcUY7NprA4muVKtTCgoPwFPLu+Q0XgNjcIBa7C1O+hGT23mWwyiAyzVOH6G33pHsJS8mI2hqA==",
+ "dependencies": {
+ "MSTest.Analyzers": "3.8.2"
+ }
+ },
+ "JetBrains.Annotations": {
+ "type": "Transitive",
+ "resolved": "2024.3.0",
+ "contentHash": "ox5pkeLQXjvJdyAB4b2sBYAlqZGLh3PjSnP1bQNVx72ONuTJ9+34/+Rq91Fc0dG29XG9RgZur9+NcP4riihTug=="
+ },
+ "Microsoft.ApplicationInsights": {
+ "type": "Transitive",
+ "resolved": "2.22.0",
+ "contentHash": "3AOM9bZtku7RQwHyMEY3tQMrHIgjcfRDa6YQpd/QG2LDGvMydSlL9Di+8LLMt7J2RDdfJ7/2jdYv6yHcMJAnNw==",
+ "dependencies": {
+ "System.Diagnostics.DiagnosticSource": "5.0.0"
+ }
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.13.0",
+ "contentHash": "9LIUy0y+DvUmEPtbRDw6Bay3rzwqFV8P4efTrK4CZhQle3M/QwLPjISghfcolmEGAPWxuJi6m98ZEfk4VR4Lfg=="
+ },
+ "Microsoft.Testing.Extensions.Telemetry": {
+ "type": "Transitive",
+ "resolved": "1.6.2",
+ "contentHash": "40oMlQzyey4jOihY0IpUufSoMYeijYgvrtIxuYmuVx1k5xl271XlP0gwD2DwAKnvmmP0cocou531d6/CB3cCIA==",
+ "dependencies": {
+ "Microsoft.ApplicationInsights": "2.22.0",
+ "Microsoft.Testing.Platform": "1.6.2"
+ }
+ },
+ "Microsoft.Testing.Extensions.TrxReport.Abstractions": {
+ "type": "Transitive",
+ "resolved": "1.6.2",
+ "contentHash": "EE4PoYoRtrTKE0R22bXuBguVgdEeepImy0S8xHaZOcGz5AuahB2i+0CV4UTefLqO1dtbA4APfumpP1la+Yn3SA==",
+ "dependencies": {
+ "Microsoft.Testing.Platform": "1.6.2"
+ }
+ },
+ "Microsoft.Testing.Extensions.VSTestBridge": {
+ "type": "Transitive",
+ "resolved": "1.6.2",
+ "contentHash": "ZvYa+VDuk39EIqyOZ/IMFSRd/N54zFBnDFmDagFBJt21vZZnSG6l/3CkJX3DvmYmuf5Byj9w7Xf46mkWuur4LQ==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.13.0",
+ "Microsoft.Testing.Extensions.Telemetry": "1.6.2",
+ "Microsoft.Testing.Extensions.TrxReport.Abstractions": "1.6.2",
+ "Microsoft.Testing.Platform": "1.6.2"
+ }
+ },
+ "Microsoft.Testing.Platform": {
+ "type": "Transitive",
+ "resolved": "1.6.2",
+ "contentHash": "7CFJKN3An5Ra6YOrTCAi7VldSRTxGGokqC0NSNrpKTKO6NJJby10EWwnqV/v2tawcRzfSbLpKNpvBv7s7ZoD3Q=="
+ },
+ "Microsoft.Testing.Platform.MSBuild": {
+ "type": "Transitive",
+ "resolved": "1.6.2",
+ "contentHash": "tF5UgrXh0b0F8N11uWfaZT91v5QvuTZDwWP19GDMHPalWFKfmlix92xExo7cotJDoAK+bzljLK0S0XJuigYLbA==",
+ "dependencies": {
+ "Microsoft.Testing.Platform": "1.6.2"
+ }
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.13.0",
+ "contentHash": "bt0E0Dx+iqW97o4A59RCmUmz/5NarJ7LRL+jXbSHod72ibL5XdNm1Ke+UO5tFhBG4VwHLcSjqq9BUSblGNWamw==",
+ "dependencies": {
+ "System.Reflection.Metadata": "1.6.0"
+ }
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.13.0",
+ "contentHash": "9GGw08Dc3AXspjekdyTdZ/wYWFlxbgcF0s7BKxzVX+hzAwpifDOdxM+ceVaaJSQOwqt3jtuNlHn3XTpKUS9x9Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.13.0",
+ "Newtonsoft.Json": "13.0.1"
+ }
+ },
+ "MSTest.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.8.2",
+ "contentHash": "ODWteXvnMEgCoZl1vAi2lOFIFFJSZkyQoQB9AFwBEUrzgJpy5J4ml3jLye4n85TA7gd+Qg2eWtqkvyEunB7B0g=="
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.1",
+ "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
+ },
+ "System.Diagnostics.DiagnosticSource": {
+ "type": "Transitive",
+ "resolved": "5.0.0",
+ "contentHash": "tCQTzPsGZh/A9LhhA6zrqCRV4hOHsK90/G7q3Khxmn6tnB1PuNU0cRaKANP2AWcF9bn0zsuOoZOSrHuJk6oNBA=="
+ },
+ "System.Reflection.Metadata": {
+ "type": "Transitive",
+ "resolved": "1.6.0",
+ "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ=="
+ },
+ "str.common": {
+ "type": "Project",
+ "dependencies": {
+ "ConfigureAwaitEnforcer": "[2.0.0, )",
+ "JetBrains.Annotations": "[2024.3.0, )"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Str.Common/Core/LockingCollection.cs b/Str.Common/Core/LockingCollection.cs
index 609cab4..5d2907e 100644
--- a/Str.Common/Core/LockingCollection.cs
+++ b/Str.Common/Core/LockingCollection.cs
@@ -1,139 +1,143 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
+using JetBrains.Annotations;
-namespace Str.Common.Core;
-[SuppressMessage("ReSharper", "MemberCanBePrivate.Global", Justification = "This is a library.")]
+namespace Str.Common.Core;
+
+[SuppressMessage("ReSharper", "MemberCanBePrivate.Global", Justification = "This is a library.")]
[SuppressMessage("ReSharper", "VirtualMemberNeverOverridden.Global", Justification = "This is a library.")]
-[SuppressMessage("ReSharper", "MemberCanBeProtected.Global", Justification = "This is a library.")]
+[SuppressMessage("ReSharper", "MemberCanBeProtected.Global", Justification = "This is a library.")]
public class LockingCollection : IList, IReadOnlyList {
- #region Constructors
+ #region Constructors
- public LockingCollection() {
- Items = new LockingList();
- }
+ public LockingCollection() {
+ Items = [];
+ }
- public LockingCollection(int capacity) {
- Items = new LockingList(capacity);
- }
+ public LockingCollection(int capacity) {
+ Items = new LockingList(capacity);
+ }
- public LockingCollection(IEnumerable enumerable) {
- Items = new LockingList(enumerable);
- }
+ public LockingCollection(IEnumerable enumerable) {
+ Items = new LockingList(enumerable);
+ }
- #endregion Constructors
+ #endregion Constructors
- #region IList Implementation
+ #region IList Implementation
- public T this[int index] {
- get => Items[index];
- set {
- if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
+ public T this[int index] {
+ get => Items[index];
+ set {
+ if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
- if ((uint)index >= (uint)Items.Count) throw new IndexOutOfRangeException();
+ if ((uint)index >= (uint)Items.Count) throw new IndexOutOfRangeException();
- SetItem(index, value);
+ SetItem(index, value);
+ }
}
- }
- public int Count => Items.Count;
+ public int Count => Items.Count;
- public void Add(T item) {
- if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
+ public void Add(T item) {
+ if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
- int index = Items.Count;
+ int index = Items.Count;
- InsertItem(index, item);
- }
+ InsertItem(index, item);
+ }
- public void Clear() {
- if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
+ public void Clear() {
+ if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
- ClearItems();
- }
+ ClearItems();
+ }
- public void CopyTo(T[] array, int index) {
- Items.CopyTo(array, index);
- }
+ public void CopyTo(T[] array, int index) {
+ Items.CopyTo(array, index);
+ }
- public bool Contains(T item) {
- return Items.Contains(item);
- }
+ public bool Contains(T item) {
+ return Items.Contains(item);
+ }
- public IEnumerator GetEnumerator() {
- return Items.GetEnumerator();
- }
+ [MustDisposeResource]
+ public IEnumerator GetEnumerator() {
+ return Items.GetEnumerator();
+ }
- public int IndexOf(T item) {
- return Items.IndexOf(item);
- }
+ public int IndexOf(T item) {
+ return Items.IndexOf(item);
+ }
- public void Insert(int index, T item) {
- if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
+ public void Insert(int index, T item) {
+ if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
- if ((uint) index >= (uint) Items.Count) throw new IndexOutOfRangeException();
+ if ((uint)index >= (uint)Items.Count) throw new IndexOutOfRangeException();
- InsertItem(index, item);
- }
+ InsertItem(index, item);
+ }
- public bool Remove(T item) {
- if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
+ public bool Remove(T item) {
+ if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
- int index = Items.IndexOf(item);
+ int index = Items.IndexOf(item);
- if (index < 0) return false;
+ if (index < 0) return false;
- RemoveItem(index);
+ RemoveItem(index);
- return true;
- }
+ return true;
+ }
- public void RemoveAt(int index) {
- if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
+ public void RemoveAt(int index) {
+ if (Items.IsReadOnly) throw new NotSupportedException("Collection is read only.");
- if ((uint) index >= (uint) Items.Count) throw new IndexOutOfRangeException();
+ if ((uint)index >= (uint)Items.Count) throw new IndexOutOfRangeException();
- RemoveItem(index);
- }
+ RemoveItem(index);
+ }
- #endregion IList Implementation
+ #endregion IList Implementation
- #region ICollection Implementation
+ #region ICollection Implementation
- bool ICollection.IsReadOnly => Items.IsReadOnly;
+ bool ICollection.IsReadOnly => Items.IsReadOnly;
- #endregion ICollection Implementation
+ #endregion ICollection Implementation
- #region IEnumerable Implementation
+ #region IEnumerable Implementation
- IEnumerator IEnumerable.GetEnumerator() {
- return (Items as IEnumerable).GetEnumerator();
- }
+ [MustDisposeResource]
+ IEnumerator IEnumerable.GetEnumerator() {
+ return (Items as IEnumerable).GetEnumerator();
+ }
- #endregion IEnumerable Implementation
+ #endregion IEnumerable Implementation
- #region Protected Methods
+ #region Protected Methods
- protected IList Items { get; }
+ protected IList Items { get; }
- protected virtual void SetItem(int index, T item) {
- Items[index] = item;
- }
+ protected virtual void SetItem(int index, T item) {
+ Items[index] = item;
+ }
- protected virtual void RemoveItem(int index) {
- Items.RemoveAt(index);
- }
+ protected virtual void RemoveItem(int index) {
+ Items.RemoveAt(index);
+ }
- protected virtual void InsertItem(int index, T item) {
- Items.Insert(index, item);
- }
+ protected virtual void InsertItem(int index, T item) {
+ Items.Insert(index, item);
+ }
- protected virtual void ClearItems() {
- Items.Clear();
- }
+ protected virtual void ClearItems() {
+ Items.Clear();
+ }
- #endregion Protected Methods
+ #endregion Protected Methods
}
\ No newline at end of file
diff --git a/Str.Common/Core/LockingList.cs b/Str.Common/Core/LockingList.cs
index f2eddd3..7332c79 100644
--- a/Str.Common/Core/LockingList.cs
+++ b/Str.Common/Core/LockingList.cs
@@ -1,6 +1,8 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
+using JetBrains.Annotations;
+
namespace Str.Common.Core;
@@ -8,234 +10,235 @@ namespace Str.Common.Core;
//
// https://codereview.stackexchange.com/questions/7276/reader-writer-collection
//
-[SuppressMessage("ReSharper", "UnusedType.Global", Justification = "This is a library.")]
-[SuppressMessage("ReSharper", "UnusedMember.Global", Justification = "This is a library.")]
+[SuppressMessage("ReSharper", "UnusedType.Global", Justification = "This is a library.")]
+[SuppressMessage("ReSharper", "UnusedMember.Global", Justification = "This is a library.")]
[SuppressMessage("ReSharper", "MemberCanBeProtected.Global", Justification = "This is a library.")]
public sealed class LockingList : IList {
- #region Private Fields
+ #region Private Fields
- private readonly List inner;
+ private readonly List inner;
- private readonly ReaderWriterLockSlim innerLock = new(LockRecursionPolicy.SupportsRecursion);
+ private readonly ReaderWriterLockSlim innerLock = new(LockRecursionPolicy.SupportsRecursion);
- #endregion Private Fields
+ #endregion Private Fields
- #region Constructors
+ #region Constructors
- public LockingList() {
- inner = new List();
- }
+ public LockingList() {
+ inner = [];
+ }
- public LockingList(int capacity) {
- inner = new List(capacity);
- }
+ public LockingList(int capacity) {
+ inner = new List(capacity);
+ }
- public LockingList(IEnumerable enumerable) {
- inner = new List(enumerable);
- }
+ public LockingList(IEnumerable enumerable) {
+ inner = [..enumerable];
+ }
- #endregion Constructors
+ #endregion Constructors
- #region IList Implementation
+ #region IList Implementation
- IEnumerator IEnumerable.GetEnumerator() {
- innerLock.EnterReadLock();
+ IEnumerator IEnumerable.GetEnumerator() {
+ innerLock.EnterReadLock();
- try {
- return new LockingEnumerator(inner.GetEnumerator(), innerLock);
- }
- finally {
- innerLock.ExitReadLock();
+ try {
+ return new LockingEnumerator(inner.GetEnumerator(), innerLock);
+ }
+ finally {
+ innerLock.ExitReadLock();
+ }
}
- }
- public IEnumerator GetEnumerator() {
- return (this as IEnumerable).GetEnumerator();
- }
-
- public void Add(T item) {
- innerLock.EnterWriteLock();
-
- try {
- inner.Add(item);
- }
- finally {
- innerLock.ExitWriteLock();
+ [MustDisposeResource]
+ public IEnumerator GetEnumerator() {
+ return (this as IEnumerable).GetEnumerator();
}
- }
- public void Clear() {
- innerLock.EnterWriteLock();
+ public void Add(T item) {
+ innerLock.EnterWriteLock();
- try {
- inner.Clear();
+ try {
+ inner.Add(item);
+ }
+ finally {
+ innerLock.ExitWriteLock();
+ }
}
- finally {
- innerLock.ExitWriteLock();
- }
- }
- public bool Contains(T item) {
- innerLock.EnterReadLock();
+ public void Clear() {
+ innerLock.EnterWriteLock();
- try {
- return inner.Contains(item);
- }
- finally {
- innerLock.ExitReadLock();
+ try {
+ inner.Clear();
+ }
+ finally {
+ innerLock.ExitWriteLock();
+ }
}
- }
- public void CopyTo(T[] array, int arrayIndex) {
- innerLock.EnterReadLock();
+ public bool Contains(T item) {
+ innerLock.EnterReadLock();
- try {
- inner.CopyTo(array, arrayIndex);
+ try {
+ return inner.Contains(item);
+ }
+ finally {
+ innerLock.ExitReadLock();
+ }
}
- finally {
- innerLock.ExitReadLock();
- }
- }
- public bool Remove(T item) {
- innerLock.EnterWriteLock();
+ public void CopyTo(T[] array, int arrayIndex) {
+ innerLock.EnterReadLock();
- try {
- return inner.Remove(item);
- }
- finally {
- innerLock.ExitWriteLock();
+ try {
+ inner.CopyTo(array, arrayIndex);
+ }
+ finally {
+ innerLock.ExitReadLock();
+ }
}
- }
- public int Count {
- get {
- innerLock.EnterReadLock();
+ public bool Remove(T item) {
+ innerLock.EnterWriteLock();
- try {
- return inner.Count;
- }
- finally {
- innerLock.ExitReadLock();
- }
+ try {
+ return inner.Remove(item);
+ }
+ finally {
+ innerLock.ExitWriteLock();
+ }
}
- }
- public bool IsReadOnly {
- get {
- innerLock.EnterReadLock();
+ public int Count {
+ get {
+ innerLock.EnterReadLock();
- try {
- return (inner as ICollection).IsReadOnly;
- }
- finally {
- innerLock.ExitReadLock();
- }
+ try {
+ return inner.Count;
+ }
+ finally {
+ innerLock.ExitReadLock();
+ }
+ }
}
- }
- public int IndexOf(T item) {
- innerLock.EnterReadLock();
+ public bool IsReadOnly {
+ get {
+ innerLock.EnterReadLock();
- try {
- return inner.IndexOf(item);
- }
- finally {
- innerLock.ExitReadLock();
+ try {
+ return (inner as ICollection).IsReadOnly;
+ }
+ finally {
+ innerLock.ExitReadLock();
+ }
+ }
}
- }
- public void Insert(int index, T item) {
- innerLock.EnterWriteLock();
+ public int IndexOf(T item) {
+ innerLock.EnterReadLock();
- try {
- inner.Insert(index, item);
+ try {
+ return inner.IndexOf(item);
+ }
+ finally {
+ innerLock.ExitReadLock();
+ }
}
- finally {
- innerLock.ExitWriteLock();
- }
- }
- public void RemoveAt(int index) {
- innerLock.EnterWriteLock();
+ public void Insert(int index, T item) {
+ innerLock.EnterWriteLock();
- try {
- inner.RemoveAt(index);
- }
- finally {
- innerLock.ExitWriteLock();
+ try {
+ inner.Insert(index, item);
+ }
+ finally {
+ innerLock.ExitWriteLock();
+ }
}
- }
- public T this[int index] {
- get {
- innerLock.EnterReadLock();
+ public void RemoveAt(int index) {
+ innerLock.EnterWriteLock();
- try {
- return inner[index];
- }
- finally {
- innerLock.ExitReadLock();
- }
+ try {
+ inner.RemoveAt(index);
+ }
+ finally {
+ innerLock.ExitWriteLock();
+ }
}
- set {
- innerLock.EnterWriteLock();
- try {
- inner[index] = value;
- }
- finally {
- innerLock.ExitWriteLock();
- }
- }
- }
+ public T this[int index] {
+ get {
+ innerLock.EnterReadLock();
- #endregion IList Implementation
+ try {
+ return inner[index];
+ }
+ finally {
+ innerLock.ExitReadLock();
+ }
+ }
+ set {
+ innerLock.EnterWriteLock();
- #region Public Properties
+ try {
+ inner[index] = value;
+ }
+ finally {
+ innerLock.ExitWriteLock();
+ }
+ }
+ }
- public int Capacity => inner.Capacity;
+ #endregion IList Implementation
- #endregion Public Properties
+ #region Public Properties
- #region Public Methods
+ public int Capacity => inner.Capacity;
- // Implement remaining List methods here.
+ #endregion Public Properties
- public void AddRange(IEnumerable collection) {
- innerLock.EnterWriteLock();
+ #region Public Methods
+ //
+ // Implement remaining List methods here.
+ //
+ public void AddRange(IEnumerable collection) {
+ innerLock.EnterWriteLock();
- try {
- inner.AddRange(collection);
- }
- finally {
- innerLock.ExitWriteLock();
+ try {
+ inner.AddRange(collection);
+ }
+ finally {
+ innerLock.ExitWriteLock();
+ }
}
- }
- public bool Exists(Predicate match) {
- innerLock.EnterReadLock();
+ public bool Exists(Predicate match) {
+ innerLock.EnterReadLock();
- try {
- return inner.Exists(match);
+ try {
+ return inner.Exists(match);
+ }
+ finally {
+ innerLock.ExitReadLock();
+ }
}
- finally {
- innerLock.ExitReadLock();
- }
- }
- public int RemoveAll(Predicate match) {
- innerLock.EnterWriteLock();
+ public int RemoveAll(Predicate match) {
+ innerLock.EnterWriteLock();
- try {
- return inner.RemoveAll(match);
- }
- finally {
- innerLock.ExitWriteLock();
+ try {
+ return inner.RemoveAll(match);
+ }
+ finally {
+ innerLock.ExitWriteLock();
+ }
}
- }
- #endregion Public Methods
+ #endregion Public Methods
}
diff --git a/Str.Common/Core/LockingObservableCollection.cs b/Str.Common/Core/LockingObservableCollection.cs
index 4be3a10..f2de2f4 100644
--- a/Str.Common/Core/LockingObservableCollection.cs
+++ b/Str.Common/Core/LockingObservableCollection.cs
@@ -3,7 +3,8 @@
using System.Diagnostics.CodeAnalysis;
-namespace Str.Common.Core;
+namespace Str.Common.Core;
+
[SuppressMessage("ReSharper", "UnusedType.Global", Justification = "This is a library.")]
[SuppressMessage("ReSharper", "UnusedMember.Global", Justification = "This is a library.")]
@@ -187,4 +188,4 @@ internal static class EventArgsCache {
internal static readonly NotifyCollectionChangedEventArgs ResetCollectionChanged = new(NotifyCollectionChangedAction.Reset);
-}
\ No newline at end of file
+}
diff --git a/Str.Common/Core/LockingReadOnlyCollection.cs b/Str.Common/Core/LockingReadOnlyCollection.cs
index 05434f9..0970e8c 100644
--- a/Str.Common/Core/LockingReadOnlyCollection.cs
+++ b/Str.Common/Core/LockingReadOnlyCollection.cs
@@ -1,93 +1,98 @@
using System.Collections;
+using JetBrains.Annotations;
+
+
+namespace Str.Common.Core;
-namespace Str.Common.Core;
public sealed class LockingReadOnlyCollection : IList, IReadOnlyList {
- #region Private Fields
+ #region Private Fields
- private readonly LockingList list;
+ private readonly LockingList list;
- private readonly NotSupportedException notSupportedException;
+ private readonly NotSupportedException notSupportedException;
- #endregion Private Fields
+ #endregion Private Fields
- #region Constructor
+ #region Constructor
- public LockingReadOnlyCollection(IEnumerable list) {
- this.list = new LockingList(list);
+ public LockingReadOnlyCollection(IEnumerable list) {
+ this.list = new LockingList(list);
- notSupportedException = new NotSupportedException("This is a Read Only Collection.");
- }
+ notSupportedException = new NotSupportedException("This is a Read Only Collection.");
+ }
- #endregion Constructor
+ #endregion Constructor
- #region ICollection Implementation
+ #region ICollection Implementation
- public int Count => list.Count;
+ public int Count => list.Count;
- public bool Contains(T value) {
- return list.Contains(value);
- }
+ public bool Contains(T value) {
+ return list.Contains(value);
+ }
- public void CopyTo(T[] array, int index) {
- list.CopyTo(array, index);
- }
+ public void CopyTo(T[] array, int index) {
+ list.CopyTo(array, index);
+ }
- public bool IsReadOnly => true;
+ public bool IsReadOnly => true;
- void ICollection.Add(T value) {
- throw notSupportedException;
- }
+ void ICollection.Add(T value) {
+ throw notSupportedException;
+ }
- void ICollection.Clear() {
- throw notSupportedException;
- }
+ void ICollection.Clear() {
+ throw notSupportedException;
+ }
- bool ICollection.Remove(T value) {
- throw notSupportedException;
- }
+ bool ICollection.Remove(T value) {
+ throw notSupportedException;
+ }
- #endregion ICollection Implementation
+ #endregion ICollection Implementation
- #region IEnumerable Implementation
+ #region IEnumerable Implementation
- public IEnumerator GetEnumerator() {
- return ((IList)list).GetEnumerator();
- }
+ [MustDisposeResource]
+ public IEnumerator GetEnumerator() {
+ return ((IList)list).GetEnumerator();
+ }
- IEnumerator IEnumerable.GetEnumerator() {
- return list.GetEnumerator();
- }
+ [MustDisposeResource]
+ IEnumerator IEnumerable.GetEnumerator() {
+ return list.GetEnumerator();
+ }
- #endregion IEnumerable Implementation
+ #endregion IEnumerable Implementation
- #region IList Implementation
+ #region IList Implementation
- public int IndexOf(T value) {
- return list.IndexOf(value);
- }
+ public int IndexOf(T value) {
+ return list.IndexOf(value);
+ }
- T IList.this[int index] {
- get => list[index];
- set => throw notSupportedException;
- }
+ T IList.this[int index] {
+ get => list[index];
+ set => throw notSupportedException;
+ }
- void IList.Insert(int index, T value) {
- throw notSupportedException;
- }
+ void IList.Insert(int index, T value) {
+ throw notSupportedException;
+ }
- void IList.RemoveAt(int index) {
- throw notSupportedException;
- }
+ void IList.RemoveAt(int index) {
+ throw notSupportedException;
+ }
- #endregion IList Implementation
+ #endregion IList Implementation
- #region IReadOnlyList Implementation
+ #region IReadOnlyList Implementation
- public T this[int index] => list[index];
+ public T this[int index] => list[index];
- #endregion IReadOnlyList Implementation
+ #endregion IReadOnlyList Implementation
}
\ No newline at end of file
diff --git a/Str.Common/Extensions/ObservableCollectionExtensions.cs b/Str.Common/Extensions/ObservableCollectionExtensions.cs
index 389f2c5..f5dba96 100644
--- a/Str.Common/Extensions/ObservableCollectionExtensions.cs
+++ b/Str.Common/Extensions/ObservableCollectionExtensions.cs
@@ -33,7 +33,7 @@ public static void OrderedMerge(this ObservableCollection list, T item) wh
public static void OrderedMerge(this ObservableCollection list, IEnumerable items) where T : IComparable {
List itemList = items.ToList();
- if (!itemList.Any()) return;
+ if (itemList.Count == 0) return;
if (!list.Any()) {
list.AddRange(itemList);
diff --git a/Str.Common/Extensions/StreamExtensions.cs b/Str.Common/Extensions/StreamExtensions.cs
index 4406132..129c791 100644
--- a/Str.Common/Extensions/StreamExtensions.cs
+++ b/Str.Common/Extensions/StreamExtensions.cs
@@ -5,8 +5,7 @@
using Str.Common.Messages;
-namespace Str.Common.Extensions;
-
+namespace Str.Common.Extensions;
//
// From an answer on Stack Overflow
//
@@ -17,78 +16,78 @@ namespace Str.Common.Extensions;
[SuppressMessage("ReSharper", "UnusedType.Global", Justification = "This is a library.")]
public static class StreamExtensions {
- private const int DefaultBufferSize = 32768;
-
- public static Task CopyToAsync(this Stream input, Stream output, int bufferSize = DefaultBufferSize, FileDownloadProgressMessage? message = null, Action?>? callback = null) where T : class {
- return input.CopyToAsync(output, bufferSize, message as FileDownloadProgressMessage, callback as Action);
- }
-
- public static async Task CopyToAsync(this Stream input, Stream output, int bufferSize = DefaultBufferSize, FileDownloadProgressMessage? message = null, Action? callback = null) {
- ValidateCopyToAsyncArguments(input, output, bufferSize);
-
- byte[][] buf = { new byte[bufferSize], new byte[bufferSize] };
-
- int[] bufl = { 0, 0 };
-
- int bufno = 0;
- int total = 0;
-
- Task read = input.ReadAsync(buf[bufno], 0, buf[bufno].Length);
-
- Task? write = null;
+ private const int DefaultBufferSize = 32768;
- while(true) {
- //
- // wait for the read operation to complete
- //
- bufl[bufno] = await read.Fire();
- //
- // if zero bytes read, the copy is complete
- //
- if (bufl[bufno] == 0) break;
-
- total += bufl[bufno];
-
- if (message != null) message.BytesCurrent = total;
-
- callback?.Invoke(message);
- //
- // wait for the in-flight write operation, if one exists, to complete
- // the only time one won't exist is after the very first read operation completes
- //
- if (write != null) await write.Fire();
- //
- // start the new write operation
- //
- write = output.WriteAsync(buf[bufno], 0, bufl[bufno]);
- //
- // toggle the current, in-use buffer
- // and start the read operation on the new buffer.
- //
- // Changed to use XOR to toggle between 0 and 1.
- // A little speedier than using a ternary expression.
- //
- bufno ^= 1; // bufno = ( bufno == 0 ? 1 : 0 ) ;
-
- read = input.ReadAsync(buf[bufno], 0, buf[bufno].Length);
+ public static async Task CopyToAsync(this Stream input, Stream output, int bufferSize = DefaultBufferSize, FileDownloadProgressMessage? message = null, Action?>? callback = null) where T : class {
+ await input.CopyToAsync(output, bufferSize, message as FileDownloadProgressMessage, callback as Action).Fire();
}
- //
- // wait for the final in-flight write operation, if one exists, to complete
- // the only time one won't exist is if the input stream is empty.
- //
- if (write != null) await write.Fire();
- if (message != null) message.IsComplete = true;
-
- callback?.Invoke(message);
- }
+ public static async Task CopyToAsync(this Stream input, Stream output, int bufferSize = DefaultBufferSize, FileDownloadProgressMessage? message = null, Action? callback = null) {
+ ValidateCopyToAsyncArguments(input, output, bufferSize);
+
+ byte[][] buf = [new byte[bufferSize], new byte[bufferSize]];
+
+ int[] bufl = [0, 0];
+
+ int bufno = 0;
+ int total = 0;
+
+ Task read = input.ReadAsync(buf[bufno], 0, buf[bufno].Length);
+
+ Task? write = null;
+
+ while (true) {
+ //
+ // wait for the read operation to complete
+ //
+ bufl[bufno] = await read.Fire();
+ //
+ // if zero bytes read, the copy is complete
+ //
+ if (bufl[bufno] == 0) break;
+
+ total += bufl[bufno];
+
+ if (message != null) message.BytesCurrent = total;
+
+ callback?.Invoke(message);
+ //
+ // wait for the in-flight write operation, if one exists, to complete
+ // the only time one won't exist is after the very first read operation completes
+ //
+ if (write != null) await write.Fire();
+ //
+ // start the new write operation
+ //
+ write = output.WriteAsync(buf[bufno], 0, bufl[bufno]);
+ //
+ // toggle the current, in-use buffer
+ // and start the read operation on the new buffer.
+ //
+ // Changed to use XOR to toggle between 0 and 1.
+ // A little speedier than using a ternary expression.
+ //
+ bufno ^= 1; // bufno = ( bufno == 0 ? 1 : 0 ) ;
+
+ read = input.ReadAsync(buf[bufno], 0, buf[bufno].Length);
+ }
+ //
+ // wait for the final in-flight write operation, if one exists, to complete
+ // the only time one won't exist is if the input stream is empty.
+ //
+ if (write != null) await write.Fire();
+
+ if (message != null) message.IsComplete = true;
+
+ callback?.Invoke(message);
+ }
- [AssertionMethod]
- private static void ValidateCopyToAsyncArguments(Stream input, Stream output, int bufferSize) {
- if (!input.CanRead) throw new InvalidOperationException("Input stream must be open for reading.");
- if (!output.CanWrite) throw new InvalidOperationException("Output stream must be open for writing.");
+ [AssertionMethod]
+ private static void ValidateCopyToAsyncArguments(Stream input, Stream output, int bufferSize) {
+ if (!input.CanRead) throw new InvalidOperationException("Input stream must be open for reading.");
+ if (!output.CanWrite) throw new InvalidOperationException("Output stream must be open for writing.");
- if (bufferSize < 1) throw new ArgumentException("Argument may not be 0 or negative.", nameof(bufferSize));
- }
+ if (bufferSize < 1) throw new ArgumentException("Argument may not be 0 or negative.", nameof(bufferSize));
+ }
}
\ No newline at end of file
diff --git a/Str.Common/Messages/ApplicationClosingMessage.cs b/Str.Common/Messages/ApplicationClosingMessage.cs
index f0f23ed..aaa337d 100644
--- a/Str.Common/Messages/ApplicationClosingMessage.cs
+++ b/Str.Common/Messages/ApplicationClosingMessage.cs
@@ -1,6 +1,5 @@
-
+namespace Str.Common.Messages;
-namespace Str.Common.Messages;
public class ApplicationClosingMessage : MessageBase {
diff --git a/Str.Common/Messages/ApplicationErrorMessage.cs b/Str.Common/Messages/ApplicationErrorMessage.cs
index f75dbb0..6ec1269 100644
--- a/Str.Common/Messages/ApplicationErrorMessage.cs
+++ b/Str.Common/Messages/ApplicationErrorMessage.cs
@@ -1,7 +1,8 @@
using System.Diagnostics.CodeAnalysis;
-namespace Str.Common.Messages;
+namespace Str.Common.Messages;
+
[SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global", Justification = "This is a library.")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global", Justification = "This is a library.")]
diff --git a/Str.Common/Messages/FileDownloadProgressMessage.cs b/Str.Common/Messages/FileDownloadProgressMessage.cs
index fbab024..78683a8 100644
--- a/Str.Common/Messages/FileDownloadProgressMessage.cs
+++ b/Str.Common/Messages/FileDownloadProgressMessage.cs
@@ -1,7 +1,8 @@
using System.Diagnostics.CodeAnalysis;
-namespace Str.Common.Messages;
+namespace Str.Common.Messages;
+
[SuppressMessage("ReSharper", "UnusedMember.Global", Justification = "This is a library.")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global", Justification = "This is a library.")]
@@ -18,6 +19,7 @@ public class FileDownloadProgressMessage : MessageBase {
}
+
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "This is a library.")]
[SuppressMessage("ReSharper", "UnusedMember.Global", Justification = "This is a library.")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global", Justification = "This is a library.")]
diff --git a/Str.Common/Messages/MessageBase.cs b/Str.Common/Messages/MessageBase.cs
index 3b09ed2..24c2fad 100644
--- a/Str.Common/Messages/MessageBase.cs
+++ b/Str.Common/Messages/MessageBase.cs
@@ -1,9 +1,8 @@
-
+namespace Str.Common.Messages;
-namespace Str.Common.Messages;
public class MessageBase {
protected MessageBase() { }
-}
\ No newline at end of file
+}
diff --git a/Str.Common/Str.Common.csproj b/Str.Common/Str.Common.csproj
index 97553d8..4fc8261 100644
--- a/Str.Common/Str.Common.csproj
+++ b/Str.Common/Str.Common.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net9.0
false
1.0.0.0
stricq
@@ -28,6 +28,7 @@
portable
true
+ true
@@ -43,7 +44,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Str.Common/packages.lock.json b/Str.Common/packages.lock.json
new file mode 100644
index 0000000..fe3988b
--- /dev/null
+++ b/Str.Common/packages.lock.json
@@ -0,0 +1,45 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net9.0": {
+ "AsyncFixer": {
+ "type": "Direct",
+ "requested": "[1.6.0, )",
+ "resolved": "1.6.0",
+ "contentHash": "/Xfs9H3UMfEv64cwT+C/JrTRp4w08BmPuFbj0ageadCHpx6rxYJxAU2C6sEqRFG22xmGk5cX9ewzoiiehWVHOw=="
+ },
+ "ConfigureAwaitEnforcer": {
+ "type": "Direct",
+ "requested": "[2.0.0, )",
+ "resolved": "2.0.0",
+ "contentHash": "jkoGjQWaD5ioGPCv/Oi/tsCEcGWfLgOHeN9IPrZbzS8epgbuBQREFlg0Oe7J6yRZuhxMyfJrSmdXtnhNgdmkLw=="
+ },
+ "JetBrains.Annotations": {
+ "type": "Direct",
+ "requested": "[2024.3.0, )",
+ "resolved": "2024.3.0",
+ "contentHash": "ox5pkeLQXjvJdyAB4b2sBYAlqZGLh3PjSnP1bQNVx72ONuTJ9+34/+Rq91Fc0dG29XG9RgZur9+NcP4riihTug=="
+ },
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ }
+ }
+ }
+}
\ No newline at end of file