Skip to content

Replace use of DAMT.All in ComponentModel with a more restricted set #114126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

MichalStrehovsky
Copy link
Member

Draft for measurements. I assume this will need API review. This is technically a breaking change. Would fix #106366.

@ghost
Copy link

ghost commented Apr 1, 2025

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost
Copy link

ghost commented Apr 1, 2025

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-componentmodel-dataannotations
See info in area-owners.md if you want to be subscribed.

@MichalStrehovsky
Copy link
Member Author

@steveharter @eerhardt any opinion about re-annotating ComponentModel with a more restricted annotation?

We used .All in multiple places of the framework whenever we needed to access private members in base type (e.g. DynamicallyAccessedMemberTypes.NonPublicMethods matches what BindingFlags.NonPublic will do and therefore doesn't look at nonpublics in the base - we had spots in ComponentModel where we walked base hierarchies looking for privates and .All was the only annotation that allowed this).

At the time ComponentModel was annotated we didn't have .AllMethods and friends.

The difference between .All and the replacement here is that .All means "all members, public and private, in bases and in implemented interfaces, and all implemented interfaces". The new annotation is "all members, public and private, in bases, and all implemented interfaces". I.e. we skip making members of interfaces available for reflection.

So if someone previously did annotatedType.GetInterfaces()[0].GetMethod("GetEnumerator") it would work. It will not work now.

I reviewed uses of GetInterface/GetInterfaces here and doesn't look like we're affected.

The only potential break here is that someone else could have taken a dependency on this being annotated .All.

A mitigating factor right now is that annotatedType.GetInterfaces()[0].GetMethod("GetEnumerator") currently generates trimming warning even if annotatedType is annotated as .All (we preserve the members, but we didn't teach dataflow analysis that this is safe). I'm fixing that in #114149 so it will become more likely someone could take advantage of this in the future.

@sbomer
Copy link
Member

sbomer commented Apr 3, 2025

The only public APIs where I see the new annotation flowing out of ComponentModel are:

  • MetadataTypeAttribute.MetadataClassType
  • RangeAttribute.OperandType
  • DbConnectionStringBuilder.GetType()

I don't see any reason those APIs would need to support getting interfaces, so I'm in favor of taking the breaking change (especially with considering the mitigating factor you mentioned).

@MichalStrehovsky
Copy link
Member Author

@steveharter @eerhardt any opinion about re-annotating ComponentModel with a more restricted annotation?

@steveharter do you have any opinion about this?

@MichalStrehovsky
Copy link
Member Author

@steveharter @eerhardt any opinion about re-annotating ComponentModel with a more restricted annotation?

@steveharter do you have any opinion about this?

We're running out of time to make this change. If we don't do this for .NET10, we'll lose the mitigating factor I mentioned above (I'll repeat it below). The breaking change would be even more breaking. The measurements over at MichalStrehovsky/rt-sz#118 (comment) suggest this could be a 6.3% size savings for for our benchmark app TodosApi when using the options validator (see #106366 for context).

A mitigating factor right now is that annotatedType.GetInterfaces()[0].GetMethod("GetEnumerator") currently generates trimming warning even if annotatedType is annotated as .All (we preserve the members, but we didn't teach dataflow analysis that this is safe). I'm fixing that in #114149 so it will become more likely someone could take advantage of this in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using Options Validation Source Generator results in increased app size
3 participants