Skip to content

Guard newer APIs to preserve netstandard2.0 compatibility - #140

Merged
wforney merged 6 commits into
mainfrom
copilot/support-netstandard20
Aug 15, 2026
Merged

Guard newer APIs to preserve netstandard2.0 compatibility#140
wforney merged 6 commits into
mainfrom
copilot/support-netstandard20

Conversation

CopilotAI commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

SharedCode.Core still targets netstandard2.0, but a few call sites had drifted to newer framework-only APIs. This change restores compatibility by keeping newer implementations on modern TFMs and using older-safe fallbacks where required.

  • String API compatibility

    • Replaced newer string comparison overload assumptions in DataReaderExtensions with framework-specific paths.
    • Kept ordinal semantics on newer targets; used older-compatible equivalents on netstandard2.0.
  • Async TextWriter fallback behavior

    • Updated BufferedWriter to use cancellable WriteAsync(..., CancellationToken)/FlushAsync(CancellationToken) where available.
    • Added fallback paths for older targets that only expose non-cancellable string-based async writes.
  • Enumeration path for older frameworks

    • Updated EnumerableExtensions.IsNotNullOrEmpty to use TryGetNonEnumeratedCount only on supported TFMs.
    • Preserved behavior on netstandard2.0 via the existing enumeration-based check.
  • Conditional framework split

    • Applied narrow #if guards instead of broad refactors so newer TFMs still take the optimized/runtime-native code paths.

Example of the compatibility pattern used:

#if NET6_0_OR_GREATERreturnsource.TryGetNonEnumeratedCount(outvarcount)?count>0:source.Any();
#else
returnsource.Any();
#endif

CopilotAIand others added 3 commits August 15, 2026 04:08
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
@wforney
wforney marked this pull request as ready for review August 15, 2026 04:16
CopilotAI lite review requested due to automatic review settings August 15, 2026 04:16

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restores SharedCode.Core’s multi-target compatibility (notably netstandard2.0) by adding narrow preprocessor guards around newer framework-only APIs, keeping optimized implementations on modern TFMs while providing older-safe fallbacks where required.

Changes:

  • Guarded EnumerableExtensions.IsNotNullOrEmpty to use TryGetNonEnumeratedCount only on supported TFMs.
  • Updated BufferedWriter async flush paths to use cancellable TextWriter.WriteAsync/FlushAsync overloads where available, with fallbacks for older targets.
  • Adjusted DataReaderExtensions.ToDelimited string comparison/replace usage to avoid newer overloads on netstandard2.0.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
SharedCode.Core/Linq/EnumerableExtensions.csAdds a TFM guard so TryGetNonEnumeratedCount is only used when available.
SharedCode.Core/IO/BufferedWriter.csUses cancellable async TextWriter overloads on newer TFMs with fallback async write/flush behavior on older TFMs.
SharedCode.Core/Data/DataReaderExtensions.csIntroduces framework-specific string-search/replace paths to preserve netstandard2.0 compatibility.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadSharedCode.Core/Data/DataReaderExtensions.cs Outdated
Comment threadSharedCode.Core/Data/DataReaderExtensions.cs Outdated
@github-actions

github-actionsBot commented Aug 15, 2026

Copy link
Copy Markdown

Summary

Summary
Generated on:8/15/2026 - 6:38:41 AM
Parser:Cobertura
Assemblies:4
Classes:195
Files:158
Line coverage:42.3% (3257 of 7699)
Covered lines:3257
Uncovered lines:4442
Coverable lines:7699
Total lines:19707
Branch coverage:24.9% (1106 of 4428)
Covered branches:1106
Total branches:4428
Method coverage:Feature is only available for sponsors

Coverage

SharedCode.Core - 27.4%
NameLineBranch
SharedCode.Core27.4%24.6%
SharedCode.AssemblyExtensions100%100%
SharedCode.Attributes.DataFormatAttribute100%100%
SharedCode.Attributes.DataWidthAttribute100%100%
SharedCode.Attributes.StringValueAttribute100%100%
SharedCode.BaseException100%50%
SharedCode.Calendar.DateTimeExtensions10.8%0.7%
SharedCode.Calendar.DateTimeOffsetExtensions70.3%44.2%
SharedCode.Calendar.DayOfWeekExtensions90.9%87.5%
SharedCode.Collections.ArrayExtensions92%73.3%
SharedCode.Collections.Generic.EnumerableExtensions0%0%
SharedCode.Collections.Generic.EnumerableExtensions0%0%
SharedCode.Collections.Generic.EnumerationUtilities100%
SharedCode.Collections.ListExtensions14.2%12.5%
SharedCode.Collections.ObservableCollectionExtensions0%0%
SharedCode.Data.DataReaderExtensions0%0%
SharedCode.Data.DataRowExtensions0%0%
SharedCode.Data.DataTableExtensions0%0%
SharedCode.DateTimeExtensions0%0%
SharedCode.DateTimeOffsetExtensions0%0%
SharedCode.Domain.Error88.8%
SharedCode.Domain.ErrorResult90.9%100%
SharedCode.Domain.ErrorResult72.7%50%
SharedCode.Domain.HttpErrorResult50%
SharedCode.Domain.Result100%
SharedCode.Domain.Result88.8%
SharedCode.Domain.ValidationError75%
SharedCode.Domain.ValidationErrorResult80%
SharedCode.Enum93.2%83.9%
SharedCode.Enum50%
SharedCode.EnumExtensions100%
SharedCode.EventArgs100%
SharedCode.EventHandlerExtensions75%75%
SharedCode.Events.DomainEvent0%
SharedCode.ExceptionExtensions51%32.7%
SharedCode.Extensions23.6%14.4%
SharedCode.Extensions23.6%14.4%
SharedCode.FluentTimeSpan66.2%71.4%
SharedCode.FunctionExtensions100%83.3%
SharedCode.FunctionExtensions<T, TResult>100%83.3%
SharedCode.IntExtensions100%100%
SharedCode.IO.BufferedWriter0%0%
SharedCode.IO.DirectoryInfoExtensions0%0%
SharedCode.IO.FileInfoExtensions0%0%
SharedCode.IO.StreamExtensions0%0%
SharedCode.IO.TcpClientExtensions0%0%
SharedCode.Linq.CollectionExtensions58%50.7%
SharedCode.Linq.CollectionExtensions.SyncChanges0%
SharedCode.Linq.CollectionExtensions<T, TKey>58%50.7%
SharedCode.Linq.CollectionExtensions58%50.7%
SharedCode.Linq.EnumerableExtensions32.9%25.4%
SharedCode.Linq.EnumerableExtensions<T, TKey>32.9%25.4%
SharedCode.Linq.EnumerableExtensions<T, TResult>32.9%25.4%
SharedCode.Linq.EnumerableExtensions32.9%25.4%
SharedCode.Linq.EnumerableExtensions<TKey, TValue>32.9%25.4%
SharedCode.Linq.EnumeratorExtensions0%0%
SharedCode.Linq.ExpressionExtensions0%0%
SharedCode.Linq.PredicateBuilder0%0%
SharedCode.Linq.Predicates100%100%
SharedCode.Linq.QueryableExtensions0%
SharedCode.Linq.QueryableExtensions0%
SharedCode.Models.Entity100%
SharedCode.Models.Entity75%75%
SharedCode.Notifications.Notification0%0%
SharedCode.Notifications.NotificationService0%0%
SharedCode.Notifications.ObservableExtensions0%0%
SharedCode.Notifications.ObservableExtensions0%0%
SharedCode.Notifications.ProducerConsumer0%0%
SharedCode.NumberExtensions100%
SharedCode.Problems.Problem0%0%
SharedCode.Problems.ProblemConstants.Types0%
SharedCode.Problems.ProblemCreationExtensions0%
SharedCode.Problems.ProblemException0%0%
SharedCode.Problems.ProblemJsonConverter0%0%
SharedCode.PropertySupport83.3%60%
SharedCode.Reflection.DeepCloneCache0%0%
SharedCode.Reflection.DeepCloneCache0%0%
SharedCode.Reflection.DeepCloneExpressionGenerator0%0%
SharedCode.Reflection.DeepCloneGenerator0%0%
SharedCode.Reflection.DeepCloneGenerator0%0%
SharedCode.Reflection.DeepCloneMsilHelper0%0%
SharedCode.Reflection.DeepCloneSafeTypes0%0%
SharedCode.Reflection.DeepCloneState0%0%
SharedCode.Reflection.DeepCloneState.MiniDictionary0%0%
SharedCode.Reflection.ExpressionGenerator0%0%
SharedCode.Reflection.GenericExtensions0%0%
SharedCode.Reflection.ShallowCloneGenerator0%0%
SharedCode.Reflection.ShallowCloneHelper0%0%
SharedCode.Reflection.ShallowCloneHelper.ShallowSafeObjectCloneHelper0%
SharedCode.Security.Hasher38.6%44.4%
SharedCode.Specifications.Builders.CacheSpecificationBuilder50%
SharedCode.Specifications.Builders.IncludableBuilderExtensions0%0%
SharedCode.Specifications.Builders.IncludableSpecificationBuilder<T, TPrope
rty>
50%
SharedCode.Specifications.Builders.OrderedBuilderExtensions50%25%
SharedCode.Specifications.Builders.OrderedSpecificationBuilder100%
SharedCode.Specifications.Builders.SpecificationBuilder<T, TResult>100%
SharedCode.Specifications.Builders.SpecificationBuilder100%
SharedCode.Specifications.Builders.SpecificationBuilderExtensions100%58.3%
SharedCode.Specifications.Evaluators.InMemorySpecificationEvaluator96.2%78.5%
SharedCode.Specifications.Evaluators.OrderEvaluator45.9%36.2%
SharedCode.Specifications.Evaluators.OrderEvaluator45.9%36.2%
SharedCode.Specifications.Evaluators.PaginationEvaluator50%37.5%
SharedCode.Specifications.Evaluators.WhereEvaluator66.6%37.5%
SharedCode.Specifications.Exceptions.DuplicateOrderChainException0%
SharedCode.Specifications.Exceptions.DuplicateSkipException25%
SharedCode.Specifications.Exceptions.DuplicateTakeException25%
SharedCode.Specifications.Exceptions.SelectorNotFoundException25%
SharedCode.Specifications.IncludeExpressionInformation69.2%40%
SharedCode.Specifications.Specification<T, TResult>100%
SharedCode.Specifications.Specification100%
SharedCode.Text.StringBuilderExtensions100%100%
SharedCode.Text.StringExtensions28.3%28.9%
SharedCode.Text.StringExtensions28.3%28.9%
SharedCode.Threading.Tasks.TaskExtensions92.8%
SharedCode.Threading.Tasks.TaskExtensions92.8%
SharedCode.Threading.Tasks.ValueTaskExtensions0%
SharedCode.Threading.Tasks.ValueTaskExtensions<TException, TResult>0%
SharedCode.Threading.Tasks.ValueTaskExtensions0%
SharedCode.Threading.Tasks.ValueTaskExtensions0%
SharedCode.TypeExtensions33.3%36%
SharedCode.TypeExtensions33.3%36%
SharedCode.Utilities0%0%
SharedCode.ValueObject80%90.9%
SharedCode.Workflow.Rule0%
SharedCode.Workflow.Rule0%
SharedCode.Workflow.RuleSet0%
SharedCode.Workflow.RuleSet0%
SharedCode.Xml.XDocumentExtensions0%0%
System.Text.RegularExpressions.Generated0%0%
System.Text.RegularExpressions.Generated.RunnerFactory
System.Text.RegularExpressions.Generated.RunnerFactory.Runner
SharedCode.Core.Tests - 98.1%
NameLineBranch
SharedCode.Core.Tests98.1%77.4%
SharedCode.Tests.AssemblyExtensionsTests100%
SharedCode.Tests.AssertExtensions0%0%
SharedCode.Tests.Attributes.AttributeTests100%100%
SharedCode.Tests.BaseExceptionTests100%
SharedCode.Tests.Calendar.DateTimeExtensionsTests96.3%100%
SharedCode.Tests.Calendar.DateTimeOffsetCalendarExtensionsTests100%
SharedCode.Tests.Calendar.DayOfWeekExtensionsTests100%
SharedCode.Tests.Collections.ArrayExtensionsTests100%100%
SharedCode.Tests.Collections.EnumerationUtilitiesTests100%
SharedCode.Tests.Domain.ErrorResultTests100%
SharedCode.Tests.Domain.ResultTests100%
SharedCode.Tests.EnumExtensionsTests100%
SharedCode.Tests.EnumTTests96.2%90%
SharedCode.Tests.EventHandlerExtensionsTests100%
SharedCode.Tests.ExceptionExtensionsTests100%
SharedCode.Tests.ExtensionsTests100%100%
SharedCode.Tests.ExtensionsTests.SampleRecord100%
SharedCode.Tests.FluentTimeSpanTests100%
SharedCode.Tests.FunctionExtensionsTests100%
SharedCode.Tests.IntExtensionsTests100%
SharedCode.Tests.LambdaComparer0%0%
SharedCode.Tests.Linq.CollectionExtensionsTests100%100%
SharedCode.Tests.Linq.EnumerableExtensionsTests100%100%
SharedCode.Tests.Linq.PredicatesTests100%
SharedCode.Tests.Models.EntityTests100%
SharedCode.Tests.NumberExtensionsTests100%
SharedCode.Tests.PropertySupportTests100%100%
SharedCode.Tests.PropertySupportTests.SampleClass100%
SharedCode.Tests.Security.HasherTests100%
SharedCode.Tests.Specifications.SpecificationTests97.7%100%
SharedCode.Tests.Specifications.SpecificationTests.BuilderExposingSpecifica
tion
100%
SharedCode.Tests.Specifications.SpecificationTests.DuplicateSkipSpecificati
on
66.6%
SharedCode.Tests.Specifications.SpecificationTests.DuplicateTakeSpecificati
on
66.6%
SharedCode.Tests.Specifications.SpecificationTests.SampleEntity100%
SharedCode.Tests.Specifications.SpecificationTests.SampleEntitySpecificatio
n
100%100%
SharedCode.Tests.Specifications.SpecificationTests.SampleProjectionSpecific
ation
100%100%
SharedCode.Tests.Specifications.SpecificationTests.SearchOnlySpecification100%
SharedCode.Tests.Text.StringBuilderExtensionsTests100%
SharedCode.Tests.Text.StringExtensionsTests100%100%
SharedCode.Tests.Threading.TaskExtensionsTests100%
SharedCode.Tests.TypeExtensionsTests100%
SharedCode.Tests.ValueObjectTests96.8%
SharedCode.Tests.ValueObjectTests.Address66.6%
SharedCode.Tests.ValueObjectTests.MoneyValue100%
TUnit.Generated.Hooks.SharedCode_Tests_Calendar_DateTimeExtensionsTests_Ini
tTestCase_Before_Test.SharedCode_Tests_Calendar_DateTimeExtensionsTests_Ini
tTestCase_Before_TestInitializer
100%
TUnit.Generated.Hooks.SharedCode_Tests_Calendar_DateTimeExtensionsTests_Tea
rdownTestCase_After_Test.SharedCode_Tests_Calendar_DateTimeExtensionsTests_
TeardownTestCase_After_TestInitializer
100%
SharedCode.Data - 8.3%
NameLineBranch
SharedCode.Data8.3%0%
SharedCode.Data.AddOrUpdateDescriptor0%
SharedCode.Data.CommandRepository0%0%
SharedCode.Data.DataReaderExtensions0%0%
SharedCode.Data.DataReaderExtensions0%0%
SharedCode.Data.DataRecordConverter0%0%
SharedCode.Data.DataServiceQueryExtensions0%0%
SharedCode.Data.DataServiceQueryExtensions0%0%
SharedCode.Data.DataServiceQueryExtensions0%0%
SharedCode.Data.DynamicDataRecord0%0%
SharedCode.Data.Exceptions.ColumnIsNotInResultSetException0%
SharedCode.Data.Extensions0%0%
SharedCode.Data.ListExtensions0%0%
SharedCode.Data.PageBoundry100%
SharedCode.Data.PagingDescriptor100%
SharedCode.Data.QueryRepository0%0%
SharedCode.Data.QueryResult100%
SharedCode.Data.Tests - 100%
NameLineBranch
SharedCode.Data.Tests100%****
SharedCode.Data.Tests.PageBoundryTests100%
SharedCode.Data.Tests.PagingDescriptorTests100%
SharedCode.Data.Tests.QueryResultTests100%

…bility
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 15, 2026 04:37
CopilotAI requested a review from wforneyAugust 15, 2026 04:38

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment threadSharedCode.Core/Data/DataReaderExtensions.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 15, 2026 06:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

SharedCode.Core/Data/DataReaderExtensions.cs:4

  • System.Globalization is already provided via the project’s global usings (SharedCode.Core/Core.csproj includes it), so this conditional using block is redundant and adds extra preprocessor complexity. Removing it keeps the file simpler without changing behavior.
#if !(NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER)
using System.Globalization;
#endif

Comment threadSharedCode.Core/Data/DataReaderExtensions.cs Outdated
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 15, 2026 06:27

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (2)

SharedCode.Core/Data/DataReaderExtensions.cs:99

  • Same nullable-conditional issue here: value?.IndexOf(separator, ...) >= 0 evaluates to bool? and won't compile in an if. Use is >= 0 (or coalesce) so null becomes false.
 // If separator is in value, ensure it is put in double quotes.
if (value?.IndexOf(separator, StringComparison.Ordinal) >= 0)
{
value = $"\"{value}\"";

SharedCode.Core/Data/DataReaderExtensions.cs:87

  • value?.IndexOf(...) >= 0 produces a nullable bool? (because of the null-conditional), which cannot be used directly in an if condition and will fail to compile. Use a relational pattern (is >= 0) (or coalesce) so null is treated as false without producing bool?.
#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
if (value?.IndexOf('"', StringComparison.Ordinal) >= 0)
#else
if (value?.IndexOf('"') >= 0)
#endif

@wforney
wforney merged commit 940588e into mainAug 15, 2026
14 checks passed
@wforney
wforney deleted the copilot/support-netstandard20 branch August 15, 2026 06:40
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@wforney