CommunityToolkit / CommunityToolkit/dotnet

[Feature] Add value sanitizers to [ObservableProperty]

Open
#1,067 1 comment 0 reactions 0 assignees View on GitHub
feature request :mailbox_with_mail:
Dominant language
C#
Stars
3.8k
Forks
400
PR merge metrics
No merged PRs in 30d

Description

### 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:

```C#
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:
```C#
[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:

```C#
[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.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

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

```C#
[ObservableProperty]
[ObservablePropertySetterMin(0)]
public partial int LapCount { get; set; }
```

```C#
[ObservableProperty]
[ObservablePropertySetterStringTrim]
[ObservablePropertySetterStringUpperCase]
public partial string Country { get; set; }
```

```C#
[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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.