Fix GenAPI omitting explicitly implemented interface events - #54492
Merged
ViktorHofer merged 3 commits intoMay 29, 2026
Merged
Conversation
Fixes dotnet#54464 GenAPI silently dropped explicit interface event implementations, causing generated reference assemblies to fail compilation with CS0535. Root causes (two layers): 1. SymbolExtensions.IsExplicitInterfaceImplementation only recognized IMethodSymbol and IPropertySymbol. Explicit-impl events have DeclaredAccessibility=Private and were filtered as private members. 2. SyntaxGeneratorExtensions.DeclarationExt routed all events through SyntaxGenerator.CustomEventDeclaration, which has no overload that accepts an ExplicitInterfaceSpecifier, so the explicit qualification was lost. Changes: * SymbolExtensions: recognize IEventSymbol explicit impls. * SyntaxGeneratorExtensions: new CreateExplicitInterfaceEventDeclaration helper emitting EventDeclarationSyntax with ExplicitInterfaceSpecifier and empty add/remove blocks. * CSharpAssemblyDocumentGenerator: mirror the existing method/property filter for events, so an explicit-impl event whose containing interface is excluded by the symbol filter is also excluded. This keeps the invariant that explicit interface implementations are part of the public API only when the underlying interface is public. * ImplicitSymbolFilter: extend the explicit-impl accessor filter to also drop EventAdd / EventRemove accessor methods, paralleling the existing PropertyGet / PropertySet handling so accessors are not emitted twice. Tests: added TestExplicitInterfaceEventGeneration and TestExplicitInterfaceEventFromInternalInterfaceIsExcluded. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes GenAPI handling for explicit interface event implementations so generated reference source includes required event members and avoids CS0535 failures.
Changes:
- Recognizes explicit interface implementations for
IEventSymbol. - Emits explicit interface event declarations directly when
SyntaxGeneratorcannot represent them. - Adds filtering and tests for explicit events, including excluded internal interfaces.
Show a summary per file
| File | Description |
|---|---|
src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/SymbolExtensions.cs |
Extends explicit-interface detection to events. |
src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/ImplicitSymbolFilter.cs |
Filters explicit event add/remove accessor methods. |
src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/SyntaxGeneratorExtensions.cs |
Adds direct syntax generation for explicit interface event declarations. |
src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/CSharpAssemblyDocumentGenerator.cs |
Filters explicit events from interfaces excluded by the symbol filter. |
test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs |
Adds GenAPI tests for explicit interface event generation and filtering. |
Copilot's findings
- Files reviewed: 5/5 changed files
- Comments generated: 1
…vent and property impls Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MemoryOutputDiffGenerator.GetMembersOfType filtered out all members lacking public/protected modifiers, which excluded explicit interface implementations (methods, properties, events, indexers). Explicit impls of public interfaces are part of the public API surface and must be reported in diffs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
akoeplinger
approved these changes
May 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.
Fixes #54464
GenAPI silently dropped explicit interface event implementations, causing generated reference assemblies to fail compilation with CS0535.
Root cause
Two layers:
SymbolExtensions.IsExplicitInterfaceImplementationonly recognizedIMethodSymbolandIPropertySymbol. Explicit-impl events haveDeclaredAccessibility=Privateand were filtered out as private members before reaching the syntax generator.SyntaxGeneratorExtensions.DeclarationExtrouted all events throughSyntaxGenerator.CustomEventDeclaration, which has no overload that accepts anExplicitInterfaceSpecifier, so the explicit qualification was lost even when the symbol made it through.Changes
IEventSymbolexplicit impls. This shared helper is used by ApiCompat, ApiDiff and GenAPI, so the fix benefits all three.CreateExplicitInterfaceEventDeclarationhelper emitsEventDeclarationSyntaxwithExplicitInterfaceSpecifierand empty add/remove blocks.EventAdd/EventRemoveaccessor methods, paralleling the existingPropertyGet/PropertySethandling so accessors are not emitted twice.Tests
TestExplicitInterfaceEventGeneration— happy path, asserts the explicit event is emitted with the correct interface qualifier.TestExplicitInterfaceEventFromInternalInterfaceIsExcluded— asserts the new filter actually drops explicit events whose underlying interface is internal.Full GenAPI test suite: 100 pass, 2 pre-existing skips, 0 failures.