/// <summary> /// Gets a <see cref="MetadataReader"/> from a <see cref="MetadataReaderProvider"/>. /// </summary> /// <remarks> /// The caller must keep the <see cref="MetadataReaderProvider"/> undisposed throughout the lifetime of the metadata reader. /// /// If this method is called multiple times each call with arguments equal to the arguments passed to the previous successful call /// returns the same instance of <see cref="MetadataReader"/> as the previous call. /// </remarks> /// <exception cref="ArgumentException">The encoding of <paramref name="utf8Decoder"/> is not <see cref="UTF8Encoding"/>.</exception> /// <exception cref="PlatformNotSupportedException">The current platform is big-endian.</exception> /// <exception cref="IOException">IO error while reading from the underlying stream.</exception> /// <exception cref="ObjectDisposedException">Provider has been disposed.</exception> public unsafe MetadataReader GetMetadataReader(MetadataReaderOptions options = MetadataReaderOptions.Default, MetadataStringDecoder utf8Decoder = null) { var cachedReader = _lazyMetadataReader; if (CanReuseReader(cachedReader, options, utf8Decoder)) { return(cachedReader); } // If multiple threads attempt to open a metadata reader with the same options and decoder // it's cheaper to wait for the other thread to finish initializing the reader than to open // two readers and discard one. // Note that it's rare to reader the same metadata using different options. lock (_metadataReaderGuard) { cachedReader = _lazyMetadataReader; if (CanReuseReader(cachedReader, options, utf8Decoder)) { return(cachedReader); } AbstractMemoryBlock metadata = GetMetadataBlock(); var newReader = new MetadataReader(metadata.Pointer, metadata.Size, options, utf8Decoder, memoryOwner: this); _lazyMetadataReader = newReader; return(newReader); } }
private static bool CanReuseReader(MetadataReader reader, MetadataReaderOptions options, MetadataStringDecoder utf8DecoderOpt) { return(reader != null && reader.Options == options && ReferenceEquals(reader.UTF8Decoder, utf8DecoderOpt ?? MetadataStringDecoder.DefaultUTF8)); }
/// <summary> /// Gets a <see cref="MetadataReader"/> from a <see cref="PEReader"/>. /// </summary> /// <remarks> /// The caller must keep the <see cref="PEReader"/> undisposed throughout the lifetime of the metadata reader. /// </remarks> /// <exception cref="ArgumentNullException"><paramref name="peReader"/> is null</exception> /// <exception cref="ArgumentException">The encoding of <paramref name="utf8Decoder"/> is not <see cref="UTF8Encoding"/>.</exception> /// <exception cref="PlatformNotSupportedException">The current platform is big-endian.</exception> /// <exception cref="IOException">IO error while reading from the underlying stream.</exception> public static unsafe MetadataReader GetMetadataReader(this PEReader peReader, MetadataReaderOptions options, MetadataStringDecoder utf8Decoder) { if (peReader == null) { throw new ArgumentNullException(nameof(peReader)); } var metadata = peReader.GetMetadata(); return(new MetadataReader(metadata.Pointer, metadata.Length, options, utf8Decoder, memoryOwner: peReader)); }