Skip to content

Conversation

@ChrisPulman
Copy link
Member

What kind of change does this PR introduce?

Feature

What is the new behavior?

Introduces WhenAnyValue and WhenAnyValueAccessModifier options to the [Reactive] attribute, enabling automatic generation of observable properties for value changes.

Updates documentation and test baselines to reflect new usage and API surface.

What might this PR break?

New feature

Please check if the PR fulfills these requirements

  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

Other information:

Introduces WhenAnyValue and WhenAnyValueAccessModifier options to the [Reactive] attribute, enabling automatic generation of observable properties for value changes. Updates documentation and test baselines to reflect new usage and API surface.
@codecov
Copy link

codecov bot commented Jan 3, 2026

Codecov Report

❌ Patch coverage is 45.76271% with 32 lines in your changes missing coverage. Please review.
✅ Project coverage is 43.24%. Comparing base (cd6e454) to head (4798549).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ators.Roslyn/Reactive/ReactiveGenerator.Execute.cs 30.43% 30 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #360      +/-   ##
==========================================
+ Coverage   43.22%   43.24%   +0.02%     
==========================================
  Files          64       64              
  Lines        3646     3702      +56     
  Branches      420      423       +3     
==========================================
+ Hits         1576     1601      +25     
- Misses       1950     1979      +29     
- Partials      120      122       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds WhenAnyValue support to the Reactive attribute, enabling automatic generation of observable properties that track value changes for reactive properties. The implementation introduces two new properties to the Reactive attribute: WhenAnyValue (bool) to enable the feature, and WhenAnyValueAccessModifier (PropertyAccessModifier enum) to control the access level of the generated observable.

Key changes:

  • Enhanced the Reactive attribute with WhenAnyValue options for automated observable generation
  • Updated the source generator to create IObservable properties named "WhenAny{PropertyName}" when enabled
  • Added comprehensive test coverage with a new test case demonstrating the feature

Reviewed changes

Copilot reviewed 69 out of 69 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/ReactiveUI.SourceGenerators.Roslyn/Reactive/ReactiveGenerator.Execute.cs Implements extraction of WhenAnyValue parameters from attributes and adds GetWhenAnyValueObservable method to generate observable properties
src/ReactiveUI.SourceGenerators.Roslyn/Reactive/Models/PropertyInfo.cs Extends PropertyInfo record with WhenAnyValue and WhenAnyValueAccessModifier fields
src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs Adds WhenAnyValue and WhenAnyValueAccessModifier properties to ReactiveAttribute definition
src/ReactiveUI.SourceGenerators.Execute/TestViewModel.cs Demonstrates usage by converting manual WhenAnyValue call to generated WhenAnyPeople observable
src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveGeneratorTests.cs Adds FromReactiveWithAnyValue test case to verify WhenAnyValue observable generation
src/ReactiveUI.SourceGenerator.Tests/REACTIVE/*.verified.cs Updates test baselines with new attribute properties and copyright year (2026)
README.md Documents the new WhenAnyValue feature with usage examples

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +313 to +322
attributeData.TryGetNamedArgument("WhenAnyValueAccessModifier", out int whenAnyValueAccessModifierArgument);
var whenAnyValueAccessModifier = whenAnyValueAccessModifierArgument switch
{
1 => "protected",
2 => "internal",
3 => "private",
4 => "protected internal",
5 => "private protected",
_ => "public",
};
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic for extracting and mapping the WhenAnyValueAccessModifier enum is duplicated between the property handling (lines 161-170) and field handling (lines 313-322) sections. This code duplication makes maintenance harder and increases the risk of inconsistencies if updates are needed. Consider extracting this logic into a separate helper method that both sections can call.

Copilot uses AI. Check for mistakes.
Comment on lines +507 to +514
$$"""
/// <summary>
/// Gets an observable for when the <see cref="{{propertyInfo.PropertyName}}"/> property
/// changes.
/// </summary>
{{propertyInfo.WhenAnyValueAccessModifier}} global::System.IObservable<{{propertyInfo.TypeNameWithNullabilityAnnotations}}> WhenAny{{propertyInfo.PropertyName}} =>
this.WhenAnyValue(x => x.{{propertyInfo.PropertyName}});
""";
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated WhenAnyValue observable property is missing the [ExcludeFromCodeCoverage] attribute that is applied to the generated reactive properties (see lines 446 and 450). For consistency with other generated members and to exclude this generated code from code coverage metrics, this attribute should be added to the WhenAnyValue observable.

Copilot uses AI. Check for mistakes.
Comment on lines +507 to +514
$$"""
/// <summary>
/// Gets an observable for when the <see cref="{{propertyInfo.PropertyName}}"/> property
/// changes.
/// </summary>
{{propertyInfo.WhenAnyValueAccessModifier}} global::System.IObservable<{{propertyInfo.TypeNameWithNullabilityAnnotations}}> WhenAny{{propertyInfo.PropertyName}} =>
this.WhenAnyValue(x => x.{{propertyInfo.PropertyName}});
""";
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated WhenAnyValue observable property is missing the [GeneratedCode] attribute that is present on the generated reactive properties (see lines 468 and 486). For consistency and to follow best practices for generated code, the WhenAnyValue observable should also include this attribute to indicate it was automatically generated.

Copilot uses AI. Check for mistakes.
@ChrisPulman ChrisPulman closed this Jan 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants