Skip to content

Commit 7b343cc

Browse files
committed
Add AccessModifier support to ReactiveCommand
Introduces the AccessModifier property to the ReactiveCommand attribute, allowing generated command properties to specify their access level. Updates documentation, attribute definitions, generator logic, and test usage to support internal, protected, private, and other modifiers.
1 parent f283e27 commit 7b343cc

File tree

5 files changed

+56
-4
lines changed

5 files changed

+56
-4
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,16 @@ ReactiveUI Source Generators automatically generate ReactiveUI objects to stream
3737
- `[ReactiveCommand(OutputScheduler = "RxApp.MainThreadScheduler")]` using a ReactiveUI Scheduler
3838
- `[ReactiveCommand(OutputScheduler = nameof(_isheduler))]` using a Scheduler defined in the class
3939
- `[ReactiveCommand][property: AttributeToAddToCommand]` with Attribute passthrough
40+
- `[ReactiveCommand(AccessModifier = PropertyAccessModifier.Internal)]` sets the access modifier of the generated command property
4041
- `[IViewFor(nameof(ViewModelName))]`
4142
- `[IViewFor<YourViewModelType>]`
4243
- `[IViewFor("YourNameSpace.YourGenericViewModel<int>")]` Generic
4344
- `[IViewFor<YourViewModelType>(RegistrationType = SplatRegistrationType.PerRequest)]` with Splat Registration Type for IViewFor registration.
4445
- `[IViewFor<YourViewModelType>(RegistrationType = SplatRegistrationType.LazySingleton)]` Generic with Splat Registration Type for IViewFor registration.
4546
- `[IViewFor<YourViewModelType>(RegistrationType = SplatRegistrationType.Constant)]` Generic with Splat Registration Type for IViewFor registration.
47+
- `[IViewFor<YourViewModelType>(ViewModelRegistrationType = SplatRegistrationType.PerRequest)]` Generic with Splat Registration Type for ViewModel registration.
48+
- `[IViewFor<YourViewModelType>(ViewModelRegistrationType = SplatRegistrationType.LazySingleton)]` Generic with Splat Registration Type for ViewModel registration.
49+
- `[IViewFor<YourViewModelType>(ViewModelRegistrationType = SplatRegistrationType.Constant)]` Generic with Splat Registration Type for ViewModel registration.
4650
- `[RoutedControlHost("YourNameSpace.CustomControl")]`
4751
- `[ViewModelControlHost("YourNameSpace.CustomControl")]`
4852
- `[BindableDerivedList]` Generates a derived list from a ReadOnlyObservableCollection backing field
@@ -544,6 +548,17 @@ public partial class MyReactiveClass
544548
}
545549
```
546550

551+
### Usage ReactiveCommand with AccessModifier
552+
```csharp
553+
using ReactiveUI.SourceGenerators;
554+
555+
public partial class MyReactiveClass
556+
{
557+
[ReactiveCommand(AccessModifier = PropertyAccessModifier.Internal)]
558+
private void Execute() { }
559+
}
560+
```
561+
547562
## Usage IViewFor `[IViewFor(nameof(ViewModelName))]`
548563

549564
### IViewFor usage

src/ReactiveUI.SourceGenerators.Execute/TestViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ protected virtual void Dispose(bool disposing)
437437
/// </summary>
438438
/// <param name="i">The i.</param>
439439
/// <returns>An Observable of int.</returns>
440-
[ReactiveCommand]
440+
[ReactiveCommand(AccessModifier = PropertyAccessModifier.Internal)]
441441
private IObservable<double?> Test8Observable(int i) => Observable.Return<double?>(i + 10.0);
442442

443443
[ReactiveCommand]

src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@ internal enum AccessModifier
4242
Init,
4343
}
4444
45+
/// <summary>
46+
/// Property Access Modifier.
47+
/// </summary>
48+
internal enum PropertyAccessModifier
49+
{
50+
Public,
51+
Protected,
52+
Internal,
53+
Private,
54+
InternalProtected,
55+
PrivateProtected,
56+
}
57+
4558
/// <summary>
4659
/// InheritanceModifier.
4760
/// </summary>
@@ -128,6 +141,14 @@ internal sealed class ReactiveCommandAttribute : global::System.Attribute
128141
/// The output scheduler.
129142
/// </value>
130143
public string? OutputScheduler { get; init; }
144+
145+
/// <summary>
146+
/// Gets the AccessModifier of the ReactiveCommand property.
147+
/// </summary>
148+
/// <value>
149+
/// The AccessModifier of the property.
150+
/// </value>
151+
public PropertyAccessModifier AccessModifier { get; init; }
131152
}
132153
#nullable restore
133154
#pragma warning restore

src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCommand/Models/CommandInfo.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ internal record CommandInfo(
1919
string? CanExecuteObservableName,
2020
CanExecuteTypeInfo? CanExecuteTypeInfo,
2121
string? OutputScheduler,
22-
EquatableArray<string> ForwardedPropertyAttributes)
22+
EquatableArray<string> ForwardedPropertyAttributes,
23+
string AccessModifier)
2324
{
2425
private const string UnitTypeName = "global::System.Reactive.Unit";
2526

src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCommand/ReactiveCommandGenerator.Execute.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,20 @@ public partial class ReactiveCommandGenerator
9191

9292
token.ThrowIfCancellationRequested();
9393

94+
// Get RegistrationType enum value from the attribute
95+
attributeData.TryGetNamedArgument("AccessModifier", out int propertyAccessModifier);
96+
var accessModifier = propertyAccessModifier switch
97+
{
98+
1 => "protected",
99+
2 => "internal",
100+
3 => "private",
101+
4 => "protected internal",
102+
5 => "private protected",
103+
_ => "public",
104+
};
105+
106+
token.ThrowIfCancellationRequested();
107+
94108
var methodSyntax = (MethodDeclarationSyntax)context.TargetNode;
95109

96110
context.GetForwardedAttributes(
@@ -118,7 +132,8 @@ public partial class ReactiveCommandGenerator
118132
canExecuteObservableName,
119133
canExecuteTypeInfo,
120134
outputScheduler,
121-
forwardedPropertyAttributes);
135+
forwardedPropertyAttributes,
136+
accessModifier);
122137
}
123138

124139
private static string GenerateSource(string containingTypeName, string containingNamespace, string containingClassVisibility, string containingType, CommandInfo[] commands)
@@ -202,7 +217,7 @@ private static string GetCommandSyntax(CommandInfo commandExtensionInfo)
202217
203218
[global::System.CodeDom.Compiler.GeneratedCode("{{GeneratorName}}", "{{GeneratorVersion}}")]
204219
{{forwardedPropertyAttributesString}}
205-
public {{RxCmd}}<{{inputType}}, {{outputType}}> {{commandName}} { get => {{initializer}} }
220+
{{commandExtensionInfo.AccessModifier}} {{RxCmd}}<{{inputType}}, {{outputType}}> {{commandName}} { get => {{initializer}} }
206221
""";
207222

208223
static string GenerateBasicCommand(CommandInfo commandExtensionInfo, string fieldName)

0 commit comments

Comments
 (0)