File: System\Reflection\Assembly.NativeAot.cs
Web Access
Project: src\runtime\src\coreclr\nativeaot\System.Private.CoreLib\src\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.Configuration.Assemblies;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Security;

using Internal.Reflection.Augments;

namespace System.Reflection
{
    public abstract partial class Assembly : ICustomAttributeProvider, ISerializable
    {
        private static Assembly? GetEntryAssemblyInternal() => Internal.Runtime.CompilerHelpers.StartupCodeHelpers.GetEntryAssembly();

        [System.Runtime.CompilerServices.Intrinsic]
        public static Assembly GetExecutingAssembly() { throw NotImplemented.ByDesign; } //Implemented by toolchain.

        [DynamicSecurityMethod]
        public static Assembly GetCallingAssembly()
        {
            if (AppContext.TryGetSwitch("Switch.System.Reflection.Assembly.SimulatedCallingAssembly", out bool isSimulated) && isSimulated)
                return GetEntryAssembly();

            if (!StackTrace.IsSupported)
                throw new NotSupportedException(SR.NotSupported_StackTraceSupportDisabled);

            // We're interested in the frame that called the method that calls GetCallingAssembly
            // (skipFrames: 2), but we walk the stack so that we can skip any compiler-generated
            // thunks that don't have method info, as well as the static constructor invocation
            // machinery (matching what CoreCLR skips when looking for the caller).
            // The for loop typically only runs one iteration.
            DiagnosticMethodInfo? dmi = null;
            for (int i = 2; ; i++)
            {
                var frame = new StackFrame(i);

                // A zero IP address means we walked off the top of the stack without finding anything.
                if (frame.GetNativeIPAddress() == IntPtr.Zero)
                    break;

                dmi = DiagnosticMethodInfo.Create(frame);
                if (dmi == null)
                    continue;

                // Skip the static constructor invocation machinery so that a GetCallingAssembly
                // called from a class constructor sees the assembly that triggered the cctor.
                if (dmi.DeclaringTypeName == $"System.Runtime.CompilerServices.{nameof(ClassConstructorRunner)}"
                    && dmi.DeclaringAssemblyName?.StartsWith(CoreLib.Name, StringComparison.Ordinal) == true)
                {
                    dmi = null;
                    continue;
                }

                break;
            }

            // If we haven't found anything, fall back to the method that called GetCallingAssembly.
            // This simulates what CoreCLR would do if GetCallingAssembly is called from e.g. Main.
            dmi ??= DiagnosticMethodInfo.Create(new StackFrame(1));

            return dmi?.DeclaringAssemblyName is string asmName ? Load(asmName) : null;
        }

        public static Assembly Load(AssemblyName assemblyRef) => ReflectionAugments.Load(assemblyRef, throwOnFileNotFound: true);

        public static Assembly Load(string assemblyString)
        {
            ArgumentNullException.ThrowIfNull(assemblyString);

            AssemblyName name = new AssemblyName(assemblyString);
            return Load(name);
        }

        // Performance metric to count the number of assemblies
        internal static uint GetAssemblyCount()
        {
            return (uint)Internal.Reflection.Core.Execution.ReflectionCoreExecution.ExecutionEnvironment.AssemblyBinder.GetLoadedAssembliesCount();
        }

        [Obsolete("Assembly.LoadWithPartialName has been deprecated. Use Assembly.Load() instead.")]
        public static Assembly LoadWithPartialName(string partialName)
        {
            ArgumentNullException.ThrowIfNull(partialName);

            if ((partialName.Length == 0) || (partialName[0] == '\0'))
                throw new ArgumentException(SR.Format_StringZeroLength, nameof(partialName));

            try
            {
                return Load(partialName);
            }
            catch (FileNotFoundException)
            {
                return null;
            }
        }
    }
}