feat(http-client-csharp): support partial method customization#10539
Merged
JoshLove-msft merged 10 commits intomicrosoft:mainfrom Apr 29, 2026
Merged
feat(http-client-csharp): support partial method customization#10539JoshLove-msft merged 10 commits intomicrosoft:mainfrom
JoshLove-msft merged 10 commits intomicrosoft:mainfrom
Conversation
Allow library authors to customize a generated method's signature by declaring a partial method in custom code. The generator detects the declaration via Roslyn syntax, applies the custom signature (modifiers, name, parameter names) to the generated implementation, marks both as `partial`, and ensures all parameters are required as required by C#. For client protocol methods, the matching happens in ScmMethodProviderCollection.BuildProtocolMethod so that the generated body references the customized parameter names. For other methods, TypeProvider.FilterCustomizedMethods performs the substitution. Refs microsoft#10526, microsoft#8627 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
commit: |
Contributor
|
No changes needing a change description found. |
…enience methods Convenience methods reference the convenience parameter providers directly when building their bodies (param conversions, request invocation, etc.). To allow renaming parameters via a partial declaration, BuildConvenienceMethod now performs the same early signature detection as BuildProtocolMethod and clones each parameter with the customer-chosen name while preserving all generator metadata (Location, WireInfo, SpreadSource, InputParameter, ...) so the body construction continues to work. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pull the partial-method matching, parameter cloning, and signature construction logic out of ScmMethodProviderCollection (and TypeProvider) into a new public PartialMethodCustomization static class in Microsoft.TypeSpec.Generator. This gives downstream emitters such as the management emitter -- which wrap ClientProviders in their own public-surface providers and so can't piggy-back on the unbranded matching logic -- a stable API to consume. Also adds a defensive throw when more than one partial declaration would match the same generated method (unreachable in well-formed C# but clearer than silently picking the first one). No behavior change for protocol or convenience methods. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds a new section to the customization guide explaining when to use partial method declarations to customize a generated method's signature, what is supported (modifier changes, parameter renames), and what is not (method renames, parameter list changes, defaults on the impl). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rtial customization tests - CanCustomizeMethodModifierOnly: verifies a partial decl that only changes the access modifier (public -> internal) without renaming parameters still produces a partial impl with the correct modifier and the generator's parameter names. - CanCustomizeConvenienceMethodSignature: covers the BuildConvenienceMethod matching/cloning path. A partial decl on the convenience overload renames p1 -> body and cancellationToken -> ct; verifies both names are applied and CancellationToken metadata is preserved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… client methods Narrows the scope explanation: the feature is targeted at protocol and convenience methods on the generated *Client class. Other generated members (models, serialization, model factories) should be customized using [CodeGenSuppress] + a hand-written replacement. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…as no custom code In FilterCustomizedMethods, only allocate the partial-declarations list when the TypeProvider actually has custom methods to inspect, and only walk it for matches when there is at least one partial declaration. This avoids one List allocation and a per-generated-method FirstOrDefault delegate allocation for the vast majority of TypeProviders that have no custom code at all. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…orted Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Derive MethodProvider.IsPartialMethod from MethodSignatureModifiers.Partial rather than carrying a separate bool, removing the redundant assignments. - Replace the local IsTypeNameMatch helper with the existing CSharpType.AreNamesEqual API, which already implements the empty-namespace fallback and additionally recurses into generic type arguments. - Avoid the [.. ConvenienceMethodParameters] allocation in BuildConvenienceMethod when no partial customization is present (common case). - Add NamedTypeSymbolProvider tests covering both the partial-declaration detection and the case where a partial method already carries a body. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
JoshLove-msft
commented
Apr 29, 2026
Move the inline C# source strings used in the new partial-method detection tests into TestData/<TestClass>/<TestMethod>/ files, matching the convention used elsewhere in NamedTypeSymbolProviderTests (e.g. ValidateSelfReferentialGenericBaseType). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jorgerangel-msft
approved these changes
Apr 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds support for customizing the signature of a generated client method (protocol or convenience) by declaring a
partialmethod in custom code. The generator detects the partial declaration and emits a matching partial implementation, applying the user''s modifiers and parameter names while keeping the generated body.Based on (and adapted from) #8627. Refs #10526.
Example
Custom code:
Generated code:
Scope
This feature is targeted at client methods (protocol and convenience methods on the generated
*Clientclass). For other generated members (models, serialization, model factories), use the existing[CodeGenSuppress]+ hand-written replacement pattern.What is supported
public→internal, addingvirtual/override).p1→content). The generator clones the parameter providers with the customer-chosen names while preserving all metadata (Location,WireInfo,SpreadSource,InputParameter, …) so the generated body keeps compiling.What is NOT supported
(method name, ordered parameter type list). A renamed partial decl will not match any generated method. Use[CodeGenSuppress]+ a hand-written method to rename, or follow up with an attribute-based opt-in (e.g.,[CodeGenName("Get")]) in a future PR.Changes
MethodProvider.IsPartialMethod— tracks partial methods.NamedTypeSymbolProvider— detectspartialmethod declarations (partial keyword + no body) via Roslyn syntax and sets thePartialmodifier on the symbol-basedMethodProvider.TypeProvider.FilterCustomizedMethods— when a generated method matches a custom partial declaration, emits a partial implementation using the custom signature + generated body, with all params forced to required. Skips its scan entirely when there are no custom methods (no extra allocations on the common path).TypeProvider.ShouldGenerate(MethodProvider)— partial declarations no longer suppress the generated method.ScmMethodProviderCollection.BuildProtocolMethodandBuildConvenienceMethod— perform the same matching before the body is built, so the body references the customer''s parameter names. Also fixes a gap in the original PR where the non-paging body still passed the generator''s parameters toCreateRequest(...).PartialMethodCustomizationstatic helper class (inMicrosoft.TypeSpec.Generator) exposingTryFindCustomSignature,RenameAndCloneParameters, andBuildPartialSignatureso downstream emitters (e.g. the management emitter, which wrapsClientProviders in its own public-surface providers) can reuse the same matching/cloning behavior in their own method builders. Throws on multiple partial decls matching the same generated method (defensive — C# itself disallows duplicate signatures).Documentation
packages/http-client-csharp/.tspd/docs/customization.md).Tests
CanCustomizeMethodSignature— protocol method parameter rename.CanCustomizeMethodModifierOnly— modifier-only customization with no parameter renames.CanCustomizeConvenienceMethodSignature— convenience method parameter rename (covers theBuildConvenienceMethodmatching/cloning path).