Repository navigation
The 3.0 release, following 0.3.2. (Versions 1.0.0 to 2.1.0 of the package ID belong to an earlier, GPL-licensed line of
the library and can't be reused.) It adds the guards people reach for first, a factory for custom exceptions, return
values and Native AOT support, and from here on SGuard keeps a stable API under Semantic Versioning. Most code upgrades
without changes; the upgrade guide covers the
rest.
Breaking changes
ThrowIf.*guards return the checked value instead ofvoid:NullOrEmpty,GreaterThan,
GreaterThanOrEqual,LessThan,LessThanOrEqualandBetween. Calls compile unchanged, but this is a binary
breaking change: an assembly compiled against 0.x that calls them must be recompiled. It is the only binary breaking
change in 3.0 (30 methods, checked with ApiCompat).GreaterThanException,GreaterThanOrEqualException,LessThanException,LessThanOrEqualExceptionand
BetweenExceptionderive fromArgumentOutOfRangeExceptioninstead of directly fromArgumentException.
catch (ArgumentException)still catches them, butcatch (ArgumentOutOfRangeException)now does too, and a
catchfor one of them placed aftercatch (ArgumentOutOfRangeException)no longer compiles (CS0160). Their
parameterless constructors have the default message ofArgumentOutOfRangeException.
Added
ThrowIf.NullandIs.Null: onlynullfails, unlikeNullOrEmpty. For a nullable value type,ThrowIf.Null
returns the underlying value.ThrowIf.NullOrWhiteSpaceandIs.NullOrWhiteSpace.ThrowIf.OutOfRangeandIs.OutOfRange, which reject values outside an inclusive range: the opposite of
Between, and the range check most code wants.ThrowIf.Negative,NegativeOrZeroandZero, and theirIs.*versions, for any number type (INumber<T>).ThrowIf.EqualandNotEqual, and theirIs.*versions, withStringComparisonoverloads for strings.ThrowIf.NotDefinedandIs.NotDefinedfor enum values that their type doesn't declare.ThrowIf.LongerThanandShorterThan, and theirIs.*versions, for string lengths. Their messages never contain
the string.Is.Url(absolutehttp/httpsURLs only),Is.CreditCard(12 to 19 digits that pass the Luhn checksum) and
Is.Match(a regular expression with a match timeout). They returnfalsefornull.- A
Func<TException>factory overload on everyThrowIf.*guard. The factory runs only when the guard fails, so a
passing guard creates no exception, and a lambda that doesn't capture variables allocates nothing. - New exceptions in
SGuard.Exceptions:NullException(anArgumentNullException),NullOrWhiteSpaceException,
andOutOfRangeException,NegativeException,NegativeOrZeroException,ZeroException,EqualException,
NotEqualException,NotDefinedException,LongerThanExceptionandShorterThanException(all
ArgumentOutOfRangeExceptions). They name the argument expressions and leave values out unless
SGuardOptions.IncludeValuesInExceptionsis on, like the existing ones. - Nullable annotations: after
ThrowIf.NullOrEmpty(x),xand the returned value are known not to be null;Is.Null,
Is.NullOrWhiteSpaceand the new validators are annotated with[NotNullWhen]; and a selector's parameter is no
longer nullable when its root is. - Roslyn analyzers in the package: SGUARD101 (
NullOrEmptyon a number orboolrejects0orfalse), SGUARD102
(an exception instance is created on every call; with a code fix that turns it into a factory), SGUARD103 (constant
BetweenorOutOfRangebounds in the wrong order) and SGUARD104 (a selector that selects a whole object). See
Analyzers. - Package validation against 0.3.2, so an accidental breaking change can't ship.
- Trimming and Native AOT support. A CI job runs the trimming and AOT analyzers and publishes a test app with Native AOT
that runs every guard.
Deprecated
- The
ThrowIf.*overloads that takeobject[] constructorArgs(SGUARD001) andExceptionActivator(SGUARD002).
They create the exception with reflection, which the compiler can't check and which breaks under trimming and Native
AOT. Pass a factory instead:() => new MyException(...). They will be removed in 4.0.
Changed
- The
NullOrEmptyselector overloads are marked[RequiresUnreferencedCode]and[RequiresDynamicCode]: selectors
don't work under Native AOT, so trimmed and AOT apps now get a warning where they call one. Nothing changes for other
apps. - An empty
Memory<T>orReadOnlyMemory<T>is detected without compiling an expression, and the bounds check of
Betweenno longer usesMakeGenericType. The bounds of a nullable struct that implements onlyIComparable<T>
(notIComparable) are no longer checked against each other; every framework type implements both.