netstandard2.1 + Modern C# Polyfills
These three projects target netstandard2.1 so the engine can ship inside Unity (which historically pinned to .NET Standard 2.1 / Mono). They use LangVersion latest so modern C# syntax (records, init-only setters, pattern matching, file-scoped namespaces, etc.) works on top of the older BCL.
Hard rules
- Never reference
net8.0-only APIs. NoSystem.Text.Json, noSystem.IO.Pipelinesoverloads added after netstandard2.1, noIUtf8SpanFormattable, noTimeProvider, noFrozenDictionary, noCollectionsMarshal.AsSpanon non-list types, no[StringSyntax]attribute, no anything fromMicrosoft.Extensions.*that requires net6+. - Polyfills bridge the gap. Look for existing polyfill files in each project (e.g.,
Polyfills/,CompilerServices/) before adding a new one. If a modern type is missing, add a minimal polyfill rather than changing the target framework. - Required attributes that need polyfills on netstandard2.1:
IsExternalInit(init setters),RequiredMemberAttribute(required members),CompilerFeatureRequiredAttribute,SetsRequiredMembersAttribute,CallerArgumentExpressionAttribute,ModuleInitializerAttribute. These are all small shims undernamespace System.Runtime.CompilerServices. Span<T>/Memory<T>are fine — netstandard2.1 has them.ValueTaskis fine — netstandard2.1 has it.IAsyncEnumerable<T>is fine — netstandard2.1 has it.ref structis fine at LangVersion latest, includingreffields (post-C# 11) — but verify the polyfill forUnscopedRefAttributeexists if you use[UnscopedRef].
Why this matters
If a Unity user pulls SECS.Engine.dll into a Unity project and it references a net8.0 type, the load will fail at runtime with a TypeLoadException that does not point at the offending API. Catching this at write-time is much cheaper than catching it at user-report-time.
When in doubt
Check each project's .csproj — <TargetFramework>netstandard2.1</TargetFramework> is the signal. The example projects (examples/valenar/Host, examples/valenar/Server, examples/valenar/Generated, benchmarks/SECS.Benchmarks) target net8.0 and are unrestricted. The polyfill rule only applies to the three library projects above.