dotnet icon indicating copy to clipboard operation
dotnet copied to clipboard

[Feature] Add value sanitizers to [ObservableProperty]

Open sn4k3 opened this issue 11 months ago • 1 comments

Overview

In many of my properties I must Clamp, Round, Max or Min the setter value. This auto defeats the [ObservableProperty] which make me implement the raw property. Example:

public double TimeoutSeconds
{
    get;
    set => SetProperty(ref field, Math.Round(
        Math.Clamp(value, 0, 10000),
        2,
        MidpointRounding.AwayFromZero)
    );
} = 5000;

Example of what I would like:

[ObservableProperty]
[ObservablePropertySetterClamp(0, 10000)]
[ObservablePropertySetterRound(2, MidpointRounding.AwayFromZero)]
public partial double TimeoutSeconds { get; set; }

API breakdown

Not sure how to make the API but I provide a sample of generated code:

[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.4.0.0")]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public partial global::System.Double TimeoutSeconds
{
    get => field;
    set
    {
        // The new sanitizer magic here
        value = Math.Clamp(value, 0, 10000);
        value = Math.Round(value, 2, MidpointRounding.AwayFromZero);
        // End

        // Current implementation, unchanged.
        if (!global::System.Collections.Generic.EqualityComparer<global::System.Double>.Default.Equals(field, value))
        {
            OnLastExecutedDateTimeChanging(value);
            OnLastExecutedDateTimeChanging(default, value);
            field = value;
            OnLastExecutedDateTimeChanged(value);
            OnLastExecutedDateTimeChanged(default, value);
            OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.LastExecutedDateTime);
        }
    }
}

Usage example

[ObservableProperty]
[ObservablePropertySetterClamp(0, 10000)]
[ObservablePropertySetterRound(2, MidpointRounding.AwayFromZero)]
public partial double TimeoutSeconds { get; set; }
[ObservableProperty]
[ObservablePropertySetterMin(0)]
public partial int LapCount { get; set; }
[ObservableProperty]
[ObservablePropertySetterStringTrim]
[ObservablePropertySetterStringUpperCase]
public partial string Country { get; set; }
[ObservableProperty]
[ObservablePropertySetterCustom(MyStaticSanitizerCallback)]
public partial string MySecretString { get; set; }

Breaking change?

No

Alternatives

The team can find a better way and/or names to do such, right now I don't see another alternative than using atributes.

Additional context

  • Also implement other sanitizers useful to other uses and types
  • If doing for setter we can also do for getter side?

Help us help you

Yes, I'd like to be assigned to work on this item

sn4k3 avatar Mar 19 '25 18:03 sn4k3

This is essentially, or could be, a duplicate of #1054. That issue would at least also solve this one.

bzd3y avatar Apr 10 '25 17:04 bzd3y