Documentation index · Contributing and building · Structuring checks · Source inclusion · Assertions · Historical performance · Background
Light.GuardClauses can be embedded as C# source when taking a dependency on the NuGet assembly is undesirable. Use either the committed portable file or the custom exporter.
Copy Light.GuardClauses.SingleFile.cs into the consuming project. It is the committed .NET Standard 2.0 distribution generated from the current sources. Its default configuration:
- changes public Light.GuardClauses types to
internal, avoiding additions to the consuming assembly's public API; - enables nullable annotations;
- retains the JetBrains contract annotations and only those code-analysis, validated-null, and caller-argument-expression support types that the portable source shape actually references;
- includes the full selected-framework assertion surface; and
- contains one flattened source shape with no conditional-compilation directives.
The generated source uses System.Collections.Immutable and span-related framework types. The consuming project must reference assemblies or packages that provide the APIs required by its target.
The exporter project can be found at tools/source-export/Light.GuardClauses.SourceCodeTransformation. It reads configuration in this order, with each later source overriding earlier values:
- built-in
SourceFileMergeOptionsdefaults; - optional
settings.jsonfrom the application's base directory; - optional
settings.local.jsonfrom the application's base directory; - command-line arguments.
The project copies both settings files from the project directory to its output directory when they exist, so dotnet run uses them regardless of the shell's working directory. The committed settings.json is the canonical complete option and assertion catalog. The optional settings.local.json is ignored by Git and is intended for local overrides.
From the repository root, a command-line override can select the modern source shape and a different output file:
dotnet run --project tools/source-export/Light.GuardClauses.SourceCodeTransformation -- \
--TargetFramework Net10_0 \
--TargetFile Light.GuardClauses.Net10.csConfiguration keys are case-insensitive. Nested command-line keys use :, for example --AssertionWhitelist:IsEnabled true.
| Option | Default | Effect |
|---|---|---|
SourceFolder |
Repository src/Light.GuardClauses |
Directory containing the source files |
TargetFile |
Root Light.GuardClauses.SingleFile.cs |
Generated output path |
TargetFramework |
NetStandard2_0 |
Selects NetStandard2_0 or Net10_0 |
ValidateGeneratedFileBuild |
true |
Builds the generated file after export; set to false to skip validation |
ChangePublicTypesToInternalTypes |
true |
Makes exported public types internal |
BaseNamespace |
Light.GuardClauses |
Rewrites the base namespace |
RemoveContractAnnotations |
false |
Removes JetBrains contract annotations from members |
RemoveNoEnumeration |
false |
Removes JetBrains NoEnumeration annotation usages |
IncludeJetBrainsAnnotations / IncludeJetBrainsAnnotationsUsing |
true |
Controls whether the JetBrains annotation types are bundled and whether their namespace is imported |
IncludeVersionComment |
true |
Adds the generated version header |
RemoveOverloadsWithExceptionFactory |
false |
Globally removes assertion overloads that accept exception factories |
| Nullable/validated-null options | varies; see settings | Include supporting attributes or remove their usages |
| Caller-argument-expression options | included/not removed | Include the portable polyfill or remove annotation usages |
AssertionWhitelist |
disabled | Optionally limits the exported assertion roots |
Use the committed settings file for the exact names and defaults of all nullable, validated-null, and caller-expression switches.
TargetFramework selects exactly one source shape:
NetStandard2_0is the portable shape used by the committed single-file distribution.Net10_0includes modern generic-math and generic IEEE 754 finiteness overloads, optimized ASCII checks, and the .NET 10 span/memory email APIs. It suppresses code-analysis and caller-argument-expression polyfills already supplied by the framework.
The parser selects the appropriate conditional branches and the merger emits no #if, #else, #endif, or other conditional-compilation directives. The result is therefore for the selected target only, not a multi-target source file.
Besides the guard-clause code itself, an export can bundle supporting attribute declarations: the JetBrains annotations, ValidatedNotNullAttribute, and the System.Diagnostics.CodeAnalysis and System.Runtime.CompilerServices polyfills that netstandard2.0 does not provide.
The inclusion options above decide which of these types the export is allowed to bundle. Which of them are actually emitted is then decided by reachability: after the configured annotation usages have been removed, the exporter binds the remaining attribute usages and keeps only the support types they reach, directly or transitively. So IncludeJetBrainsAnnotations and the polyfill inclusion options mean "provide the support types this export needs", not "provide all of them". Three consequences are worth knowing:
- The JetBrains
NotNullAttributeis only emitted as a dependency ofContractAnnotationAttribute. The[NotNull]usages on assertion parameters resolve toSystem.Diagnostics.CodeAnalysis.NotNullAttribute, soRemoveContractAnnotationsremoves both JetBrains types at once and also drops theNotNullAttributealias directive that disambiguates them. - When no JetBrains annotation type survives, the
JetBrains.Annotationsnamespace, its license banner, andusing JetBrains.Annotations;are all omitted. - A whitelisted export drops the support types that its retained assertions do not annotate, even though the exporter processes the bundled declaration files as a whole.
IncludeJetBrainsAnnotationsUsing is independent of this trimming while IncludeJetBrainsAnnotations is false: the generated file then imports JetBrains.Annotations without declaring it, and the consuming project has to supply the annotation types itself, for example through the JetBrains.Annotations NuGet package. Turn IncludeJetBrainsAnnotationsUsing off as well and use RemoveContractAnnotations plus RemoveNoEnumeration to obtain a file with no JetBrains dependency at all.
When AssertionWhitelist.IsEnabled is false, all entry settings are ignored and the full surface for the selected framework is exported.
When enabled, entries whose Include value is true become reachability roots. The exporter retains their transitive dependencies, including required members of Check and Throw, exception types, attributes, exception-factory delegates, and supporting helpers. Unrelated public helpers and assertion APIs may be omitted.
Every entry defaults to Include: true. To create a genuinely small subset, start with the complete catalog in the committed settings.json, enable the whitelist, set every unwanted entry to false, and keep only the required roots. A shortened illustration of the resulting local file is:
{
"TargetFramework": "Net10_0",
"AssertionWhitelist": {
"IsEnabled": true,
"MustNotBeNull": {
"Include": true,
"IncludeExceptionFactoryOverload": false
},
"MustNotBeEmpty": {
"Include": true,
"IncludeExceptionFactoryOverload": true
}
}
}For this example to select only those two roots, all other catalog entries must be present with "Include": false; omitted entries remain enabled by default. This default is intentionally fail-safe.
For example, jq can turn the committed full catalog into that exact local subset without listing every exclusion by hand:
jq '
.TargetFramework = "Net10_0" |
.AssertionWhitelist.IsEnabled = true |
(.AssertionWhitelist[] | select(type == "object") | .Include) = false |
.AssertionWhitelist.MustNotBeNull = {
"Include": true,
"IncludeExceptionFactoryOverload": false
} |
.AssertionWhitelist.MustNotBeEmpty = {
"Include": true,
"IncludeExceptionFactoryOverload": true
}
' tools/source-export/Light.GuardClauses.SourceCodeTransformation/settings.json \
> tools/source-export/Light.GuardClauses.SourceCodeTransformation/settings.local.json
dotnet run --project tools/source-export/Light.GuardClauses.SourceCodeTransformationRemoveOverloadsWithExceptionFactory is the global switch. When it is false, an included whitelist entry can still remove its factory overload with IncludeExceptionFactoryOverload: false. The per-entry value cannot restore factory overloads removed globally.
The exporter fails loudly if a Check.<Name>.cs assertion file has no corresponding whitelist property. This keeps the catalog synchronized even while whitelist mode is disabled.
After writing the target file, the tool builds it through Light.GuardClauses.SourceValidation using netstandard2.0 or net10.0 to match the selected source target. Set ValidateGeneratedFileBuild to false to skip this validation when the caller will validate the output separately.
If generation throws, the tool prints the exception and returns a non-zero exit code. If validation fails, it prints the captured build output and returns the build's non-zero exit code. In either case, a file already generated is left in place for diagnosis. Do not publish or commit custom output unless the command and matching validation complete successfully.