File: System\Reflection\TypeLoading\Assemblies\Ecma\EcmaAssembly.cs
Web Access
Project: src\src\libraries\System.Reflection.MetadataLoadContext\src\System.Reflection.MetadataLoadContext.csproj (System.Reflection.MetadataLoadContext)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
 
namespace System.Reflection.TypeLoading.Ecma
{
    /// <summary>
    /// Base class for all Assembly objects created by a MetadataLoadContext and get its metadata from a PEReader.
    /// </summary>
    internal sealed partial class EcmaAssembly : RoAssembly
    {
        private readonly string _location;
        private readonly EcmaModule _manifestModule;
 
        internal EcmaAssembly(MetadataLoadContext loader, PEReader peReader, MetadataReader reader, string location)
            : base(loader, reader.AssemblyFiles.Count)
        {
            Debug.Assert(loader != null);
            Debug.Assert(peReader != null);
            Debug.Assert(reader != null);
            Debug.Assert(location != null);
 
            _location = location;
            _neverAccessThisExceptThroughAssemblyDefinitionProperty = reader.GetAssemblyDefinition();
 
            _manifestModule = new EcmaModule(this, location, peReader, reader);
        }
 
        internal sealed override RoModule GetRoManifestModule() => _manifestModule;
        internal EcmaModule GetEcmaManifestModule() => _manifestModule;
 
        public sealed override MethodInfo? EntryPoint => GetEcmaManifestModule().ComputeEntryPoint(fileRefEntryPointAllowed: true);
 
        public sealed override string ImageRuntimeVersion => Reader.MetadataVersion;
        public sealed override bool IsDynamic => false;
        public sealed override string Location => _location;
 
        public sealed override IEnumerable<CustomAttributeData> CustomAttributes => AssemblyDefinition.GetCustomAttributes().ToTrueCustomAttributes(GetEcmaManifestModule());
 
        protected sealed override AssemblyNameData[] ComputeAssemblyReferences()
        {
            MetadataReader reader = Reader;
            AssemblyNameData[] assemblyReferences = new AssemblyNameData[reader.AssemblyReferences.Count];
            int index = 0;
            foreach (AssemblyReferenceHandle handle in reader.AssemblyReferences)
            {
                AssemblyReference ar = handle.GetAssemblyReference(reader);
                AssemblyNameData data = new AssemblyNameData();
 
                AssemblyNameFlags flags = ar.Flags.ToAssemblyNameFlags();
                data.Flags = flags;
                data.Name = ar.Name.GetString(reader);
                data.Version = ar.Version.AdjustForUnspecifiedVersionComponents()!;
                data.CultureName = ar.Culture.GetStringOrNull(reader) ?? string.Empty;
                if ((flags & AssemblyNameFlags.PublicKey) != 0)
                {
                    byte[] pk = ar.PublicKeyOrToken.GetBlobBytes(reader);
                    data.PublicKey = pk;
                    if (pk.Length != 0)
                    {
                        // AssemblyName will automatically compute the PKT on demand but given that we're doing all this work and caching it, we might
                        // as well do this now.
                        data.PublicKeyToken = pk.ComputePublicKeyToken();
                    }
                }
                else
                {
                    data.PublicKeyToken = ar.PublicKeyOrToken.GetBlobBytes(reader);
                }
 
                assemblyReferences[index++] = data;
            }
 
            return assemblyReferences;
        }
 
        protected sealed override void IterateTypeForwards(TypeForwardHandler handler)
        {
            MetadataReader reader = Reader;
            foreach (ExportedTypeHandle exportedTypeHandle in reader.ExportedTypes)
            {
                ExportedType exportedType = reader.GetExportedType(exportedTypeHandle);
                if (!exportedType.IsForwarder)
                    continue;
 
                EntityHandle implementation = exportedType.Implementation;
                if (implementation.Kind != HandleKind.AssemblyReference) // This check also weeds out nested types. This is intentional.
                    continue;
 
                RoAssembly redirectedAssembly = ((AssemblyReferenceHandle)implementation).ResolveToAssemblyOrExceptionAssembly(GetEcmaManifestModule());
                ReadOnlySpan<byte> ns = exportedType.Namespace.AsReadOnlySpan(reader);
                ReadOnlySpan<byte> name = exportedType.Name.AsReadOnlySpan(reader);
                handler(redirectedAssembly, ns, name);
            }
        }
 
        internal MetadataReader Reader => _manifestModule.Reader;
 
        private ref readonly AssemblyDefinition AssemblyDefinition { get { Loader.DisposeCheck(); return ref _neverAccessThisExceptThroughAssemblyDefinitionProperty; } }
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]  // Block from debugger watch windows so they don't AV the debugged process.
        private readonly AssemblyDefinition _neverAccessThisExceptThroughAssemblyDefinitionProperty;
    }
}