AOT-safe System.ComponentModel.DataAnnotations validation, extracted from the Stunts data-annotation behavior so it can run without a proxy pipeline.
Namespace Devlooped.DataAnnotations.
NativeValidatoris the caller-facing surface, shaped likeSystem.ComponentModel.DataAnnotations.Validator.TryValidateObject/ValidateObjectandTryValidateProperty/ValidatePropertyuse aValidationContext.Try*returns bool and appendsValidationResults.Validate*throwsValidationExceptionfor the first failure.TryValidateObjectdefaults to required properties only.- The per-check methods (
Required,StringLength, and the rest) are theIsValidlayer. A bad value returnsValidationResult, including a value of the wrong type. Malformed bounds still throwInvalidOperationException. TryValidate/Validate(instance, method, arguments)run the rules registered for a method or constructor.Validatorhas no equivalent.NativeValidation.Register,RegisterProperties, andRegisterTypeare the generator entries. Lookups key a member by declaring type, metadata name (set_Email,Save,.ctor), andNativeValidationSignature. Property getters are emitted so object validation does not reflect.ValidatedAttributeon a generic factory, a generic method that carries aValidationAttributesubclass, and[assembly: Validate<T>], close open generic targets the syntax walk cannot see.
NativeValidation.Generator ships inside the package at analyzers/dotnet/cs. It emits Devlooped.Generated.NativeValidationRegistrations when the compilation can see Devlooped.DataAnnotations.NativeValidation. buildTransitive/NativeValidation.targets sets NativeValidatorAnalyzer to that DLL. Analyzers do not flow through a package dependency, so a downstream package adds $(NativeValidatorAnalyzer) when the annotated types live in the consuming compilation.
Supported attributes match the built-in set enforced by NativeValidator, including CustomValidationAttribute as a direct static call. Any other ValidationAttribute subclass warns as NVA001 and is not enforced. NVA002 reports a supported attribute the generator had to skip.
Instance properties (via the setter), methods, and constructors are registered, including non-virtual members. Static members, out parameters, ref structs, and pointers are skipped.
src/Tests references the generator as an analyzer, so runtime tests execute the module initializer. Closure tests drive NativeValidationGenerator against an in-memory compilation.
src/Sample is an AOT-compatible console app with a large annotated order model. Its build runs the trim and AOT analyzers over the generated registrations.