bartoszlenar / Validot

Validot is a performance-first, compact library for advanced model validation. Using a simple declarative fluent interface, it efficiently handles classes, structs, nested members, collections, nullables, plus any relation or combination of them. It also supports translations, custom logic extensions with tests, and DI containers.
MIT License
298 stars 18 forks source link

Nullable reference types support #30

Open adambajguz opened 1 year ago

adambajguz commented 1 year ago

.NET slowly transisions to code that uses nullable reference types. It would be great if Validot supports nullable reference types.

Problem:

public record Model
{
    public string? Language { get; init; }
}

public sealed class ModelValidator : ISpecificationHolder<Model>
{
    public Specification<Model> Specification { get; }

    public ModelValidator()
    {
        Specification = m => m
            .Member(x => x.Language!, language => language // must use a null forgiving operator to use the IsLanguageCode extension 
                .IsLanguageCode()
            );
    }
}

public static IRuleOut<string> IsLanguageCode(this IRuleIn<string> @this) // string doesn't allow a null
{
    // some code
}

I can replace IRuleIn<string> with IRuleIn<string?> but "If the value entering the scope is null, scope commands are not executed." (DOCUMENTATION.md#null-policy) and using null forgiving operator is for me awful.

Nullable support in .NET Standard 2.0

Nullable package can be used to add nullable reference types to .NET Standard and/or a multi-target package can be created (I've never checked how e.g. .NET 6 handles nullable annotations from .NET Standard 2.0 package because I've always used multi-targeted packages so this need verification).

 <PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
    <Nullable>annotations</Nullable>
  </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1'">
    <PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="all" />
  </ItemGroup>
bartoszlenar commented 1 year ago

Hi @adambajguz , thank you for pointing this out.

Yes, I've been thinking about it intensively for a year now. Recently, after releasing 2.3, I made a decision and because thanks to you there is an issue about nullable reference types, I feel obliged to share my plans for Validot in that matter.

Two statements to start with:

What's the solution, then?

What's the plan?

I'll release two or three versions with as many features (for sure #5 and #26) as I can code within reasonable amount of time. So let's say there will be 2.5, 2.6 and 2.7 still targeting .NET Standard 2.0. This way I'll ensure that features achievable now are available for the broader audience with legacy projects.

Only then I'll redirect my efforts to making version 3.0, which will include native support for nullable reference types on top of other minor breaking changes.

adambajguz commented 1 year ago

Sounds like a reasonable plan! Thanks for sharing it!