File: src\libraries\System.Private.CoreLib\src\System\Reflection\Assembly.cs
Web Access
Project: src\src\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj (System.Private.CoreLib)
// 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.ComponentModel;
using System.Configuration.Assemblies;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
using System.Runtime.Serialization;
using System.Security;
 
namespace System.Reflection
{
    public abstract partial class Assembly : ICustomAttributeProvider, ISerializable
    {
        private static readonly Dictionary<string, Assembly> s_loadfile = new Dictionary<string, Assembly>();
        private static readonly List<string> s_loadFromAssemblyList = new List<string>();
        private static bool s_loadFromHandlerSet;
        private static int s_cachedSerializationSwitch;
 
        protected Assembly() { }
 
        public virtual IEnumerable<TypeInfo> DefinedTypes
        {
            [RequiresUnreferencedCode("Types might be removed")]
            get
            {
                Type[] types = GetTypes();
                TypeInfo[] typeinfos = new TypeInfo[types.Length];
                for (int i = 0; i < types.Length; i++)
                {
                    typeinfos[i] = types[i].GetTypeInfo() ?? throw new NotSupportedException(SR.Format(SR.NotSupported_NoTypeInfo, types[i].FullName));
                }
                return typeinfos;
            }
        }
 
        [RequiresUnreferencedCode("Types might be removed")]
        public virtual Type[] GetTypes()
        {
            Module[] m = GetModules(false);
            if (m.Length == 1)
            {
                return m[0].GetTypes();
            }
 
            int finalLength = 0;
            Type[][] moduleTypes = new Type[m.Length][];
 
            for (int i = 0; i < moduleTypes.Length; i++)
            {
                moduleTypes[i] = m[i].GetTypes();
                finalLength += moduleTypes[i].Length;
            }
 
            int current = 0;
            Type[] ret = new Type[finalLength];
            for (int i = 0; i < moduleTypes.Length; i++)
            {
                int length = moduleTypes[i].Length;
                Array.Copy(moduleTypes[i], 0, ret, current, length);
                current += length;
            }
 
            return ret;
        }
 
        public virtual IEnumerable<Type> ExportedTypes
        {
            [RequiresUnreferencedCode("Types might be removed")]
            get => GetExportedTypes();
        }
        [RequiresUnreferencedCode("Types might be removed")]
        public virtual Type[] GetExportedTypes() { throw NotImplemented.ByDesign; }
        [RequiresUnreferencedCode("Types might be removed")]
        public virtual Type[] GetForwardedTypes() { throw NotImplemented.ByDesign; }
 
        internal const string ThrowingMessageInRAF = "This member throws an exception for assemblies embedded in a single-file app";
 
        [Obsolete("Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility. Use Assembly.Location.", DiagnosticId = "SYSLIB0012", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
        [RequiresAssemblyFiles(ThrowingMessageInRAF)]
        public virtual string? CodeBase => throw NotImplemented.ByDesign;
        public virtual MethodInfo? EntryPoint => throw NotImplemented.ByDesign;
        public virtual string? FullName => throw NotImplemented.ByDesign;
        public virtual string ImageRuntimeVersion => throw NotImplemented.ByDesign;
        public virtual bool IsDynamic => false;
        public virtual string Location => throw NotImplemented.ByDesign;
        public virtual bool ReflectionOnly => throw NotImplemented.ByDesign;
        public virtual bool IsCollectible => true;
 
        public virtual ManifestResourceInfo? GetManifestResourceInfo(string resourceName) { throw NotImplemented.ByDesign; }
        public virtual string[] GetManifestResourceNames() { throw NotImplemented.ByDesign; }
        public virtual Stream? GetManifestResourceStream(string name) { throw NotImplemented.ByDesign; }
        public virtual Stream? GetManifestResourceStream(Type type, string name) { throw NotImplemented.ByDesign; }
 
        public bool IsFullyTrusted => true;
 
        public virtual AssemblyName GetName() => GetName(copiedName: false);
        public virtual AssemblyName GetName(bool copiedName) { throw NotImplemented.ByDesign; }
 
        [RequiresUnreferencedCode("Types might be removed by trimming. If the type name is a string literal, consider using Type.GetType instead.")]
        public virtual Type? GetType(string name) => GetType(name, throwOnError: false, ignoreCase: false);
        [RequiresUnreferencedCode("Types might be removed by trimming. If the type name is a string literal, consider using Type.GetType instead.")]
        public virtual Type? GetType(string name, bool throwOnError) => GetType(name, throwOnError: throwOnError, ignoreCase: false);
        [RequiresUnreferencedCode("Types might be removed by trimming. If the type name is a string literal, consider using Type.GetType instead.")]
        public virtual Type? GetType(string name, bool throwOnError, bool ignoreCase) { throw NotImplemented.ByDesign; }
 
        public virtual bool IsDefined(Type attributeType, bool inherit) { throw NotImplemented.ByDesign; }
 
        public virtual IEnumerable<CustomAttributeData> CustomAttributes => GetCustomAttributesData();
        public virtual IList<CustomAttributeData> GetCustomAttributesData() { throw NotImplemented.ByDesign; }
 
        public virtual object[] GetCustomAttributes(bool inherit) { throw NotImplemented.ByDesign; }
        public virtual object[] GetCustomAttributes(Type attributeType, bool inherit) { throw NotImplemented.ByDesign; }
 
        [Obsolete("Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility. Use Assembly.Location.", DiagnosticId = "SYSLIB0012", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
        [RequiresAssemblyFiles(ThrowingMessageInRAF)]
        public virtual string EscapedCodeBase => AssemblyName.EscapeCodeBase(CodeBase);
 
        [RequiresUnreferencedCode("Assembly.CreateInstance is not supported with trimming. Use Type.GetType instead.")]
        public object? CreateInstance(string typeName) => CreateInstance(typeName, false, BindingFlags.Public | BindingFlags.Instance, binder: null, args: null, culture: null, activationAttributes: null);
 
        [RequiresUnreferencedCode("Assembly.CreateInstance is not supported with trimming. Use Type.GetType instead.")]
        public object? CreateInstance(string typeName, bool ignoreCase) => CreateInstance(typeName, ignoreCase, BindingFlags.Public | BindingFlags.Instance, binder: null, args: null, culture: null, activationAttributes: null);
 
        [RequiresUnreferencedCode("Assembly.CreateInstance is not supported with trimming. Use Type.GetType instead.")]
        public virtual object? CreateInstance(string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object[]? args, CultureInfo? culture, object[]? activationAttributes)
        {
            Type? t = GetType(typeName, throwOnError: false, ignoreCase: ignoreCase);
            if (t == null)
                return null;
 
            return Activator.CreateInstance(t, bindingAttr, binder, args, culture, activationAttributes);
        }
 
        public virtual event ModuleResolveEventHandler? ModuleResolve { add { throw NotImplemented.ByDesign; } remove { throw NotImplemented.ByDesign; } }
 
        public virtual Module ManifestModule => throw NotImplemented.ByDesign;
        public virtual Module? GetModule(string name) { throw NotImplemented.ByDesign; }
 
        public Module[] GetModules() => GetModules(getResourceModules: false);
        public virtual Module[] GetModules(bool getResourceModules) { throw NotImplemented.ByDesign; }
 
        public virtual IEnumerable<Module> Modules => GetLoadedModules(getResourceModules: true);
        public Module[] GetLoadedModules() => GetLoadedModules(getResourceModules: false);
        public virtual Module[] GetLoadedModules(bool getResourceModules) { throw NotImplemented.ByDesign; }
 
        [RequiresUnreferencedCode("Assembly references might be removed")]
        public virtual AssemblyName[] GetReferencedAssemblies() { throw NotImplemented.ByDesign; }
 
        public virtual Assembly GetSatelliteAssembly(CultureInfo culture) { throw NotImplemented.ByDesign; }
        public virtual Assembly GetSatelliteAssembly(CultureInfo culture, Version? version) { throw NotImplemented.ByDesign; }
 
        [RequiresAssemblyFiles(ThrowingMessageInRAF)]
        public virtual FileStream? GetFile(string name) { throw NotImplemented.ByDesign; }
        [RequiresAssemblyFiles(ThrowingMessageInRAF)]
        public virtual FileStream[] GetFiles() => GetFiles(getResourceModules: false);
        [RequiresAssemblyFiles(ThrowingMessageInRAF)]
        public virtual FileStream[] GetFiles(bool getResourceModules) { throw NotImplemented.ByDesign; }
 
        [Obsolete(Obsoletions.LegacyFormatterImplMessage, DiagnosticId = Obsoletions.LegacyFormatterImplDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { throw NotImplemented.ByDesign; }
 
        public override string ToString()
        {
            return FullName ?? base.ToString()!;
        }
 
        /*
          Returns true if the assembly was loaded from the global assembly cache.
        */
        [Obsolete(Obsoletions.GlobalAssemblyCacheMessage, DiagnosticId = Obsoletions.GlobalAssemblyCacheDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
        public virtual bool GlobalAssemblyCache => throw NotImplemented.ByDesign;
        public virtual long HostContext => throw NotImplemented.ByDesign;
 
        public override bool Equals(object? o) => base.Equals(o);
        public override int GetHashCode() => base.GetHashCode();
 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator ==(Assembly? left, Assembly? right)
        {
            // Test "right" first to allow branch elimination when inlined for null checks (== null)
            // so it can become a simple test
            if (right is null)
            {
                return left is null;
            }
 
            // Try fast reference equality and opposite null check prior to calling the slower virtual Equals
            if (ReferenceEquals(left, right))
            {
                return true;
            }
 
            return (left is null) ? false : left.Equals(right);
        }
 
        public static bool operator !=(Assembly? left, Assembly? right) => !(left == right);
 
        public static string CreateQualifiedName(string? assemblyName, string? typeName) => typeName + ", " + assemblyName;
 
        public static Assembly? GetAssembly(Type type)
        {
            if (type is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.type);
            }
 
            return type.Module?.Assembly;
        }
 
        private static object? s_overriddenEntryAssembly;
 
        /// <summary>
        /// Sets the application's entry assembly to the provided assembly object.
        /// </summary>
        /// <param name="assembly">
        /// Assembly object that represents the application's new entry assembly.
        /// </param>
        /// <remarks>
        /// The assembly passed to this function has to be a runtime defined Assembly
        /// type object. Otherwise, an exception will be thrown.
        /// </remarks>
        public static void SetEntryAssembly(Assembly? assembly)
        {
            if (assembly is null)
            {
                s_overriddenEntryAssembly = string.Empty;
                return;
            }
 
            if (assembly is not RuntimeAssembly)
                throw new ArgumentException(SR.Argument_MustBeRuntimeAssembly);
 
            s_overriddenEntryAssembly = assembly;
        }
 
        public static Assembly? GetEntryAssembly()
        {
            if (s_overriddenEntryAssembly is not null)
                return s_overriddenEntryAssembly as Assembly;
 
            return GetEntryAssemblyInternal();
        }
 
        [RequiresUnreferencedCode("Types and members the loaded assembly depends on might be removed")]
        public static Assembly Load(byte[] rawAssembly) => Load(rawAssembly, rawSymbolStore: null);
 
        // Loads the assembly with a COFF based IMAGE containing
        // an emitted assembly. The assembly is loaded into a fully isolated ALC with resolution fully deferred to the AssemblyLoadContext.Default.
        // The second parameter is the raw bytes representing the symbol store that matches the assembly.
        [RequiresUnreferencedCode("Types and members the loaded assembly depends on might be removed")]
        public static Assembly Load(byte[] rawAssembly, byte[]? rawSymbolStore)
        {
            ArgumentNullException.ThrowIfNull(rawAssembly);
 
            if (rawAssembly.Length == 0)
                throw new BadImageFormatException(SR.BadImageFormat_BadILFormat);
 
            SerializationInfo.ThrowIfDeserializationInProgress("AllowAssembliesFromByteArrays",
                ref s_cachedSerializationSwitch);
 
            AssemblyLoadContext alc = new IndividualAssemblyLoadContext("Assembly.Load(byte[], ...)");
            return alc.InternalLoad(rawAssembly, rawSymbolStore);
        }
 
        [RequiresUnreferencedCode("Types and members the loaded assembly depends on might be removed")]
        public static Assembly LoadFile(string path)
        {
            ArgumentNullException.ThrowIfNull(path);
 
            if (PathInternal.IsPartiallyQualified(path))
            {
                throw new ArgumentException(SR.Format(SR.Argument_AbsolutePathRequired, path), nameof(path));
            }
 
            string normalizedPath = Path.GetFullPath(path);
 
            Assembly? result;
            lock (s_loadfile)
            {
                if (s_loadfile.TryGetValue(normalizedPath, out result))
                    return result;
 
                // we cannot check for file presence on BROWSER. The files could be embedded and not physically present.
#if !TARGET_BROWSER && !TARGET_WASI
                if (!File.Exists(normalizedPath))
                    throw new FileNotFoundException(SR.Format(SR.FileNotFound_LoadFile, normalizedPath), normalizedPath);
#endif // !TARGET_BROWSER && !TARGET_WASI
 
                AssemblyLoadContext alc = new IndividualAssemblyLoadContext($"Assembly.LoadFile({normalizedPath})");
                result = alc.LoadFromAssemblyPath(normalizedPath);
                s_loadfile.Add(normalizedPath, result);
            }
            return result;
        }
 
        [RequiresUnreferencedCode("Types and members the loaded assembly depends on might be removed")]
        [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file",
            Justification = "The assembly is loaded by specifying a path outside of the single-file bundle, the location of the path will not be empty if the path exist, otherwise it will be handled as null")]
        private static Assembly? LoadFromResolveHandler(object? sender, ResolveEventArgs args)
        {
            Assembly? requestingAssembly = args.RequestingAssembly;
            if (requestingAssembly == null)
            {
                return null;
            }
 
            // Requesting assembly for LoadFrom is always loaded in defaultContext - proceed only if that
            // is the case.
            if (AssemblyLoadContext.Default != AssemblyLoadContext.GetLoadContext(requestingAssembly))
                return null;
 
            // Get the path where requesting assembly lives and check if it is in the list
            // of assemblies for which LoadFrom was invoked.
            string requestorPath = requestingAssembly.Location;
            if (string.IsNullOrEmpty(requestorPath))
                return null;
 
            requestorPath = Path.GetFullPath(requestorPath);
 
            lock (s_loadFromAssemblyList)
            {
                // If the requestor assembly was not loaded using LoadFrom, exit.
                if (!s_loadFromAssemblyList.Contains(requestorPath))
                {
#if CORECLR
                    if (AssemblyLoadContext.IsTracingEnabled())
                    {
                        AssemblyLoadContext.TraceAssemblyLoadFromResolveHandlerInvoked(args.Name, false, requestorPath, null);
                    }
#endif // CORECLR
                    return null;
                }
            }
 
            // Requestor assembly was loaded using loadFrom, so look for its dependencies
            // in the same folder as it.
            // Form the name of the assembly using the path of the assembly that requested its load.
            AssemblyName requestedAssemblyName = new AssemblyName(args.Name!);
            string requestedAssemblyPath = Path.Combine(Path.GetDirectoryName(requestorPath)!, requestedAssemblyName.Name + ".dll");
#if CORECLR
            if (AssemblyLoadContext.IsTracingEnabled())
            {
                AssemblyLoadContext.TraceAssemblyLoadFromResolveHandlerInvoked(args.Name, true, requestorPath, requestedAssemblyPath);
            }
#endif // CORECLR
            try
            {
                // Avoid a first-chance exception by checking for file presence first.
                // we cannot check for file presence on BROWSER. The files could be embedded and not physically present.
#if !TARGET_BROWSER && !TARGET_WASI
                if (!File.Exists(requestedAssemblyPath))
                {
                    return null;
                }
#endif // !TARGET_BROWSER && !TARGET_WASI
 
                // Load the dependency via LoadFrom so that it goes through the same path of being in the LoadFrom list.
                return LoadFrom(requestedAssemblyPath);
            }
            catch (FileNotFoundException)
            {
                // Catch FileNotFoundException when attempting to resolve assemblies via this handler to account for missing assemblies.
                // This is necessary even with the above exists check since a file might be removed between the check and the load.
                return null;
            }
        }
 
        [RequiresUnreferencedCode("Types and members the loaded assembly depends on might be removed")]
        public static Assembly LoadFrom(string assemblyFile)
        {
            ArgumentNullException.ThrowIfNull(assemblyFile);
 
            string fullPath = Path.GetFullPath(assemblyFile);
 
            if (!s_loadFromHandlerSet)
            {
                lock (s_loadFromAssemblyList)
                {
                    if (!s_loadFromHandlerSet)
                    {
                        AssemblyLoadContext.AssemblyResolve += LoadFromResolveHandler!;
                        s_loadFromHandlerSet = true;
                    }
                }
            }
 
            // Add the path to the LoadFrom path list which we will consult
            // before handling the resolves in our handler.
            lock (s_loadFromAssemblyList)
            {
                if (!s_loadFromAssemblyList.Contains(fullPath))
                {
                    s_loadFromAssemblyList.Add(fullPath);
                }
            }
 
            return AssemblyLoadContext.Default.LoadFromAssemblyPath(fullPath);
        }
 
        [RequiresUnreferencedCode("Types and members the loaded assembly depends on might be removed")]
        [Obsolete(Obsoletions.LoadFromHashAlgorithmMessage, DiagnosticId = Obsoletions.LoadFromHashAlgorithmDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
        public static Assembly LoadFrom(string assemblyFile, byte[]? hashValue, AssemblyHashAlgorithm hashAlgorithm)
        {
            throw new NotSupportedException(SR.NotSupported_AssemblyLoadFromHash);
        }
 
        [RequiresUnreferencedCode("Types and members the loaded assembly depends on might be removed")]
        public static Assembly UnsafeLoadFrom(string assemblyFile) => LoadFrom(assemblyFile);
 
        [RequiresUnreferencedCode("Types and members the loaded module depends on might be removed")]
        public Module LoadModule(string moduleName, byte[]? rawModule) => LoadModule(moduleName, rawModule, null);
        [RequiresUnreferencedCode("Types and members the loaded module depends on might be removed")]
        public virtual Module LoadModule(string moduleName, byte[]? rawModule, byte[]? rawSymbolStore) { throw NotImplemented.ByDesign; }
 
        [Obsolete(Obsoletions.ReflectionOnlyLoadingMessage, DiagnosticId = Obsoletions.ReflectionOnlyLoadingDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
        [RequiresUnreferencedCode("Types and members the loaded assembly depends on might be removed")]
        public static Assembly ReflectionOnlyLoad(byte[] rawAssembly) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_ReflectionOnly); }
        [Obsolete(Obsoletions.ReflectionOnlyLoadingMessage, DiagnosticId = Obsoletions.ReflectionOnlyLoadingDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
        [RequiresUnreferencedCode("Types and members the loaded assembly depends on might be removed")]
        public static Assembly ReflectionOnlyLoad(string assemblyString) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_ReflectionOnly); }
        [Obsolete(Obsoletions.ReflectionOnlyLoadingMessage, DiagnosticId = Obsoletions.ReflectionOnlyLoadingDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
        [RequiresUnreferencedCode("Types and members the loaded assembly depends on might be removed")]
        public static Assembly ReflectionOnlyLoadFrom(string assemblyFile) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_ReflectionOnly); }
 
        public virtual SecurityRuleSet SecurityRuleSet => SecurityRuleSet.None;
    }
}