Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ protected MetadataAssemblyResolver() { }
public sealed partial class MetadataLoadContext : System.IDisposable
{
public MetadataLoadContext(System.Reflection.MetadataAssemblyResolver resolver, string? coreAssemblyName = null) { }
public System.Reflection.Assembly? CoreAssembly { get { throw null; } }
public System.Reflection.Assembly CoreAssembly { get { throw null; } }
Comment thread
jkotas marked this conversation as resolved.
public void Dispose() { }
public System.Collections.Generic.IEnumerable<System.Reflection.Assembly> GetAssemblies() { throw null; }
public System.Reflection.Assembly LoadFromAssemblyName(System.Reflection.AssemblyName assemblyName) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ public MetadataLoadContext(MetadataAssemblyResolver resolver, string? coreAssemb
}

// Resolve the core assembly now
_coreTypes = new CoreTypes(this, coreAssemblyName);
_coreAssembly = LoadCoreAssembly(coreAssemblyName);
_coreTypes = new CoreTypes(_coreAssembly);
}
Comment thread
teo-tsirpanis marked this conversation as resolved.

/// <summary>
Expand Down Expand Up @@ -205,8 +206,7 @@ public Assembly LoadFromAssemblyName(AssemblyName assemblyName)
/// The core assembly is treated differently than other assemblies because references to these well-known types do
/// not include the assembly reference, unlike normal types.
///
/// Typically, this assembly is named "mscorlib", or "netstandard". If the core assembly cannot be found, the value will be
/// null and many other reflection methods, including those that parse method signatures, will throw.
/// Typically, this assembly is named "System.Runtime", "mscorlib", or "netstandard".
///
/// The CoreAssembly is determined by passing the coreAssemblyName parameter passed to the MetadataAssemblyResolver constructor
/// to the MetadataAssemblyResolver's Resolve method.
Comment on lines 211 to 212
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

The docs say the coreAssemblyName parameter is “passed to the MetadataAssemblyResolver constructor”, but coreAssemblyName is a MetadataLoadContext constructor parameter and is what gets passed to MetadataAssemblyResolver.Resolve. Please correct this wording to avoid confusing API consumers.

Copilot uses AI. Check for mistakes.
Expand All @@ -220,13 +220,6 @@ public Assembly LoadFromAssemblyName(AssemblyName assemblyName)
/// such as DllImportAttribute. However, it can serve if you have no interest in those attributes. The CustomAttributes api
/// will skip those attributes if the core assembly does not include the necessary types.
///
/// The CoreAssembly is not loaded until necessary. These APIs do not trigger the search for the core assembly:
/// MetadataLoadContext.LoadFromStream(), LoadFromAssemblyPath(), LoadFromByteArray()
/// Assembly.GetName(), Assembly.FullName, Assembly.GetReferencedAssemblies()
/// Assembly.GetTypes(), Assembly.DefinedTypes, Assembly.GetExportedTypes(), Assembly.GetForwardedTypes()
/// Assembly.GetType(string, bool, bool)
/// Type.Name, Type.FullName, Type.AssemblyQualifiedName
///
/// If a core assembly cannot be found or if the core assembly is missing types, this will affect the behavior of the MetadataLoadContext as follows:
///
Comment on lines 223 to 224
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

The XML docs still describe behavior when a core assembly cannot be found, but MetadataLoadContext now resolves the core assembly during construction and throws if it can’t be resolved. Please update this section to reflect that failure to resolve the core assembly results in an exception at construction time, and keep the remaining guidance focused on the “core assembly missing types” case (which can still happen).

Copilot uses AI. Check for mistakes.
/// - Apis that need to parse signatures or typespecs and return the results as Types will throw. For example,
Expand All @@ -240,7 +233,7 @@ public Assembly LoadFromAssemblyName(AssemblyName assemblyName)
/// type, the necessary constructor or any of the parameter types of the constructor, the MetadataLoadContext will not throw. It will omit the pseudo-custom
/// attribute from the list of returned attributes.
/// </summary>
public Assembly? CoreAssembly
public Assembly CoreAssembly
{
get
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,25 @@ public sealed partial class MetadataLoadContext
{
private static readonly string[] s_CoreNames = { "mscorlib", "System.Runtime", "netstandard" };

// Cache loaded coreAssembly and core types.
internal RoAssembly? TryGetCoreAssembly(string? coreAssemblyName, out Exception? e)
internal RoAssembly LoadCoreAssembly(string? coreAssemblyName)
{
Debug.Assert(_coreAssembly == null);
RoAssembly? coreAssembly;
Comment on lines +14 to +16
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

LoadCoreAssembly no longer uses Debug/System.Diagnostics in this file. Please remove the now-unused using System.Diagnostics; directive to avoid CS8019 warnings (which may be treated as errors in this repo’s build settings).

Copilot uses AI. Check for mistakes.
Exception? e;
if (coreAssemblyName == null)
{
_coreAssembly = TryGetDefaultCoreAssembly(out e);
coreAssembly = TryGetDefaultCoreAssembly(out e);
}
else
{
RoAssemblyName roAssemblyName = new AssemblyName(coreAssemblyName).ToRoAssemblyName();
_coreAssembly = TryResolveAssembly(roAssemblyName, out e);
coreAssembly = TryResolveAssembly(roAssemblyName, out e);
}

return _coreAssembly;
if (coreAssembly == null)
{
throw e!;
}
return coreAssembly;
}

private RoAssembly? TryGetDefaultCoreAssembly(out Exception? e)
Expand All @@ -47,7 +51,7 @@ public sealed partial class MetadataLoadContext
return null;
}

private RoAssembly? _coreAssembly;
private readonly RoAssembly _coreAssembly;

/// <summary>
/// Returns a lazily created and cached Type instance corresponding to the indicated core type. This method throws
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,19 @@ internal sealed class CoreTypes
private readonly RoType?[] _coreTypes;
private readonly Exception?[] _exceptions;

internal CoreTypes(MetadataLoadContext loader, string? coreAssemblyName)
internal CoreTypes(RoAssembly coreAssembly)
{
int numCoreTypes = (int)CoreType.NumCoreTypes;
RoType?[] coreTypes = new RoType[numCoreTypes];
Exception?[] exceptions = new Exception[numCoreTypes];
RoAssembly? coreAssembly = loader.TryGetCoreAssembly(coreAssemblyName, out Exception? e);
if (coreAssembly == null)
for (int i = 0; i < numCoreTypes; i++)
{
// If the core assembly was not found, don't continue.
throw e!;
}
else
{
for (int i = 0; i < numCoreTypes; i++)
((CoreType)i).GetFullName(out ReadOnlySpan<byte> ns, out ReadOnlySpan<byte> name);
RoType? type = coreAssembly.GetTypeCore(ns, name, ignoreCase: false, out Exception? e);
coreTypes[i] = type;
if (type == null)
{
((CoreType)i).GetFullName(out ReadOnlySpan<byte> ns, out ReadOnlySpan<byte> name);
RoType? type = coreAssembly.GetTypeCore(ns, name, ignoreCase: false, out e);
coreTypes[i] = type;
if (type == null)
{
exceptions[i] = e;
}
exceptions[i] = e;
}
}
_coreTypes = coreTypes;
Expand Down
Loading