You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Drop netstandard2.0, target net8.0 and net10.0 LTS
- Convert all Regex fields to [GeneratedRegex] on partial methods
- Convert BusinessDay and DateTimeRange to record types
- Convert AgeSpan to readonly record struct
- Embrace immutability: IReadOnlyList, FrozenDictionary, get/init properties
- Enable nullable reference types and implicit usings
- Use String./Int32./Char. for static method calls per project convention
- Use ReadOnlySpan<char> in TimeUnit and Helper for zero-alloc parsing
- Restore all contextual comments stripped during modernization
- Preserve public API: restore protected virtual Validate on BusinessWeek
- Upgrade test project to xUnit v3 with Microsoft Testing Platform
Co-authored-by: Cursor <cursoragent@cursor.com>
- Use modern C# features compatible with **netstandard2.0**: be mindful of API availability
114
+
- Use modern C# features available in **net8.0/net10.0**
115
+
-**Nullable reference types** are enabled—annotate nullability correctly, don't suppress warnings without justification
116
+
-**ImplicitUsings** are enabled—don't add `using System;`, `using System.Collections.Generic;`, etc.
115
117
- Follow SOLID, DRY principles; remove unused code and parameters
116
118
- Clear, descriptive naming; prefer explicit over clever
117
-
- Use `ConfigureAwait(false)` in library code (not in tests)
119
+
120
+
### Modern .NET Idioms
121
+
122
+
-**Source-generated regexes**: Use `[GeneratedRegex]` on `partial` methods instead of `new Regex(...)` or `RegexOptions.Compiled`
123
+
-**Record types**: Use `record` for immutable data types; use `readonly record struct` for small value types
124
+
-**Frozen collections**: Use `FrozenDictionary` / `FrozenSet` for immutable lookup collections initialized once
125
+
-**Guard APIs**: Use `ArgumentNullException.ThrowIfNull()`, `ArgumentException.ThrowIfNullOrEmpty()`, `ArgumentOutOfRangeException.ThrowIfGreaterThan()` etc. instead of manual null/range checks
126
+
-**Range/Index syntax**: Prefer `[..^N]`, `[start..end]` over `Substring` calls
127
+
-**Pattern matching**: Use `is`, `switch` expressions, and property patterns where they improve clarity
118
128
119
129
### Parsing & Date Math Patterns
120
130
121
-
-**Regex-based parsing**: Part parsers expose a `Regex` property; format parsers use regex internally
131
+
-**Source-generated regex parsing**: Part parsers expose regex via `[GeneratedRegex]` partial methods; format parsers use source-generated regex internally
122
132
-**Priority ordering**: Lower `[Priority]` values run first—put more specific/common parsers earlier
123
133
-**Timezone preservation**: When parsing dates with explicit timezones (`Z`, `+05:00`), always preserve the original offset
124
134
-**Upper/lower limit rounding**: `/d` rounds to start of day for lower limits, end of day for upper limits
@@ -143,8 +153,9 @@ The library uses a **priority-ordered parser chain** for `DateTimeRange.Parse()`
143
153
### Performance Considerations
144
154
145
155
-**Avoid allocations in hot paths**: Parsing methods are called frequently; minimize string allocations
146
-
-**Compiled regex**: Use `RegexOptions.Compiled` for frequently-used patterns
147
-
-**Span-based parsing**: Where compatible with netstandard2.0, prefer span-based approaches
156
+
-**Source-generated regex**: Use `[GeneratedRegex]` for all regex patterns—generates optimized code at compile time, avoiding runtime compilation overhead
157
+
-**Frozen collections**: Use `FrozenDictionary` / `FrozenSet` for lookup tables that are initialized once and read many times
158
+
-**Span-based parsing**: Prefer `ReadOnlySpan<char>` and span-based approaches for parsing hot paths
148
159
-**Profile before optimizing**: Don't guess—measure
149
160
-**Cache parser instances**: Parsers are discovered once via reflection and reused
150
161
@@ -202,7 +213,7 @@ Before marking work complete, verify:
202
213
203
214
### Error Handling
204
215
205
-
-**Validate inputs**: Check for null, empty strings, invalid ranges at method entry
216
+
-**Validate inputs**: Use `ArgumentNullException.ThrowIfNull()`, `ArgumentException.ThrowIfNullOrEmpty()`, and `ArgumentOutOfRangeException.ThrowIfGreaterThan()` etc. at method entry
206
217
-**Fail fast**: Throw exceptions immediately for invalid arguments (don't propagate bad data)
207
218
-**Meaningful messages**: Include parameter names and expected values in exception messages
208
219
-**TryParse pattern**: Always provide a `TryParse` alternative that returns `bool` instead of throwing
@@ -220,7 +231,7 @@ Tests are not just validation—they're **executable documentation** and **desig
220
231
221
232
### Framework
222
233
223
-
-**xUnit** as the primary testing framework
234
+
-**xUnit v3**with **Microsoft Testing Platform**as the test runner
224
235
-**Foundatio.Xunit** provides `TestWithLoggingBase` for test output logging
225
236
- Follow [Microsoft unit testing best practices](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices)
0 commit comments