[API Proposal]: Make DynamicallyAccessedMembers valid for Type/string collection parameters
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
### Background and motivation
`[DynamicallyAccessedMembers]` is valid for pure `Type`/`string` parameters, but not for collections, whose element type is `Type` or `string`.
Consider the following example:
```csharp
// In safe mode polymorphic deserialization does not resolve type names in the serialization stream,
// even if they present with their assembly qualified name. All types that are not supported natively
// by the serializer must be enlisted in the expectedCustomTypes parameter.
// TRoot (along with its type arguments if it is a generic type) are automatically included in expectedCustomTypes
public TRoot DeserializeSafe(XmlReader reader, params Type[] expectedCustomTypes)
{
// [...]
{
```
As of today, such an API cannot be made AOT-compatible, because I can apply `[DynamicallyAccessedMembers]` for `TRoot` only, but not for `expectedCustomTypes`:
```
warning IL2098: Parameter 'expectedCustomTypes' of method 'DeserializeSafe`1(XmlReader, params Type[])' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to parameters of type 'System.Type' or 'System.String'.
```
### API Proposal
No actual change is needed for the `DynamicallyAccessedMembersAttribute` - the change affects the trimming only
### API Usage
By accepting the proposal, this would become valid:
```cs
private const DynamicallyAccessedMemberTypes neededMembers = DynamicallyAccessedMemberTypes.AllConstructors
| DynamicallyAccessedMemberTypes.PublicFields
| DynamicallyAccessedMemberTypes.PublicProperties;
public TRoot DeserializeSafe<[DynamicallyAccessedMembers(neededMembers)]TRoot>( // nothing new here
XmlReader reader,
[DynamicallyAccessedMembers(neededMembers)]params Type[] expectedCustomTypes) // no IL2098 anymore
{
// [...]
{
```
And then an AOT-friendly usage could use `typeof()` expressions passed to the `expectedCustomTypes` parameter:
```cs
var myObj = xmlSerializer.DeserializeSafe(xmlStream, typeof(MyEmbeddedType1), typeof(MyEmbeddedType2));
```
### Alternative Designs
- #114044 is something similar, but for the generic arguments only. Implementing that one as well could simplify using a generic `TRoot` with custom types in the example, but it's not really necessary for this proposal, because we still can make this API work by enlisting also the type arguments in the `expectedTypes` parameter.
- #129415 is also similar, but it intends to enlist explicit member names for a single type rather than multiple types.
### Risks
?
Contributor guide
Research direction
Start by reading the proposed DynamicallyAccessedMembers usage and the related issues #114044 and #129415, then trace the trimming validation that produces IL2098 for collection parameters. Done means the proposed Type[] and string collection annotations are accepted by trimming analysis and the shown AOT-friendly usage no longer produces IL2098.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend-api-design, compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100