Skip to content

Conversation

@lordmilko
Copy link
Contributor

@lordmilko lordmilko commented Jun 1, 2025

Problem

System.Reflection.Metadata allows specifying a System.Reflection.Metadata.MetadataStringDecoder to your MetadataReader to cache any strings it allocates, thereby reducing allocations.

I have an existing MetadataReader that is using my custom MetadataStringDecoder, however ICSharpCode.Decompiler.Metadata.MetadataFile does not allow me to pass in my existing MetadataReader, it instead requires that I pass in a System.Reflection.Metadata.MetadataReaderProvider.

If MetadataReaderProvider.GetMetadataReader is called multiple times with the same inputs, the same MetadataReader will be returned each time. I thought that maybe I could create a MetadataReaderProvider to get the MetadataReader that I and ICSharpCode.Decompiler both need to use, however GetMetadataReader does not return its cached MetadataReader if it is called multiple times with different arguments. GetMetadataReader allows specifying a MetadataStringDecoder to it, however, ICSharpCode.Decompiler does not support this, which means

  • it's not possible for me to have a single MetadataReader that is shared by ICSharpCode.Decompiler and code that runs outside of it
  • ICSharpCode.Decompiler will create a lot of extra string allocations in my program that could be avoided with the use of MetadataStringDecoder

Solution

There are two potential ways this can be solved

  • Add an optional MetadataStringDecoder parameter to existing code paths that lead to the creation of a MetadataFile
  • Add an overload to MetadataFile that allows specifying an existing MetadataReader directly

The former approach works well with the PEReader type, which derives from MetadataFile, while the latter works better when you're handling PE parsing yourself and want to interact with MetadataFile directly. As such, I have implemented both approaches.

utf8Decoder is the name that System.Reflection.Metadata gives to MetadataStringDecoder parameters, so I have used the same name

}

private protected MetadataFile(MetadataFileKind kind, string fileName, PEReader reader, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default)
public MetadataFile(MetadataFileKind kind, string fileName, MetadataReader metadataReader, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default, int metadataOffset = 0, bool isEmbedded = false)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The metadataOptions parameter is unused in this overload.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this. I have pushed an additional commit that corrects this

@siegfriedpammer
Copy link
Member

Overall, I think this is a good idea. I don't remember why I didn't add the MetadataReader overload when doing the initial refactoring. Maybe I had some concerns regarding the "ownership" of the MetadataReader instance, but as it doesn't implement IDisposable this is not a problem, I think.

@siegfriedpammer siegfriedpammer merged commit 0bfe222 into icsharpcode:master Jun 19, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants