microsoft / microsoft/typespec
[http-client-csharp] Support declarative generated property transformations without full replacement
- Dominant language
- Java
- Stars
- 5.9k
- Forks
- 394
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 104
Description
## Feature request
Allow C# customization code to modify individual aspects of a generated property without replacing and reimplementing the entire property.
Today, `[CodeGenMember("OriginalName")]` is applied to a custom property declaration and replaces the generated property. Even when the desired change is only a rename, accessibility adjustment, or setter addition, the customization must take ownership of the complete declaration and implementation.
For example, renaming a property currently requires repeating its type, accessors, initialization behavior, documentation, and sometimes its backing field:
```csharp
[CodeGenMember("OriginalName")]
public BicepValue NewName
{
get { Initialize(); return _value; }
set { Initialize(); _value.Assign(value); }
}
```
This is cumbersome and fragile. It can also discard generator-owned metadata or behavior and prevents future generator improvements from flowing into the customized member. Azure/azure-sdk-for-net#62602 is a concrete example where replacement properties and generated wire metadata interact poorly.
## Proposed direction
Support declarative transformations on a generated member while retaining the original generated `PropertyProvider`, body, metadata, attributes, documentation, and serialization information.
One possible syntax would allow repeatable attributes on the containing partial type:
```csharp
[CodeGenMember("OriginalName", "NewName")]
[CodeGenMember("InternalProperty", Accessibility = CodeGenAccessibility.Public)]
[CodeGenMember("GetterOnlyProperty", SetterAccessibility = CodeGenAccessibility.Public)]
public partial class ExampleModel
{
}
```
Alternatively, a separate attribute could avoid overloading the existing replacement semantics:
```csharp
[CodeGenMemberCustomization(
"OriginalName",
Name = "NewName",
Accessibility = CodeGenAccessibility.Public,
SetterAccessibility = CodeGenAccessibility.Public)]
public partial class ExampleModel
{
}
```
The exact API is open for discussion. The important distinction is that these declarations should transform the generated member rather than replace it.
## Initial scenarios
- Rename a generated property while preserving its serialized name and all wire metadata.
- Change property accessibility, such as `internal` to `public`.
- Add or change setter accessibility when the generator can produce a valid setter implementation.
- Add or change getter accessibility.
- Combine transformations without copying the full property into custom code.
If a requested transformation cannot be implemented safely—for example, adding a setter when there is no valid assignment path—the generator should report a diagnostic rather than require a silently incomplete implementation.
## Expected benefits
- Smaller, intention-revealing customization files.
- Generated metadata and serialization behavior remain attached to the property.
- Generator fixes and implementation improvements continue to flow through customizations.
- Less duplicated accessor and backing-field logic.
- Reduced risk of API compatibility customizations diverging from generated behavior.
Contributor guide
Research direction
Start by tracing the existing CodeGenMember replacement path and the generated PropertyProvider model. Review how generated metadata, accessors, documentation, and serialization information are retained, then define tests for the listed rename and accessibility scenarios. Done means transformations preserve generated behavior and report a diagnostic when an unsafe setter change is requested.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- devtools
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100