-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
Description
In MetadataLoadContext, calling GetGenericArguments() on a Type object returns an array instance of type RoType[] (an internal implementation type) rather than a standard Type[].
This causes issues in code that expects the returned array to be a strict Type[].
For example, as shown in the reproduction code below, calling AsSpan() on the result of GetGenericArguments() throws an ArrayTypeMismatchException.
This occurs because AsSpan<Type>() cannot be called on an array that is physically RoType[], even though RoType inherits from Type, due to array covariance limitations with spans.
Reproduction Steps
using System.Reflection;
using System.Runtime.InteropServices;
using var mlc = new MetadataLoadContext(
new PathAssemblyResolver([
Assembly.GetExecutingAssembly().Location,
.. Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll")
])
);
// Use MetadataLoadContext.LoadFromAssemblyPath to load the executing assembly and
// get the Type of the following class C<T1, T2>.
var a = mlc.LoadFromAssemblyPath(Assembly.GetExecutingAssembly().Location);
// var a = Assembly.GetExecutingAssembly();
var t = a.GetType(typeof(C<,>).FullName!, throwOnError: true)!;
Console.WriteLine(t.GetType());
Console.WriteLine($"Return type of GetGenericArguments: {t.GetGenericArguments().GetType()}");
Console.WriteLine($"GetGenericArguments: {string.Join(", ", t.GetGenericArguments().AsSpan())}");
class C<T1, T2> { }As shown in the "Actual behavior" section, this code throws an ArrayTypeMismatchException when calling AsSpan().
Expected behavior
Type.GetGenericArguments() should return a Type[], and calling AsSpan() should succeed without throwing an exception.
Return type of GetGenericArguments: System.Type[]
GetGenericArguments: T1, T2
Actual behavior
Type.GetGenericArguments() returns RoType[], which leads to an ArrayTypeMismatchException when AsSpan() is invoked.
Return type of GetGenericArguments: System.Reflection.TypeLoading.RoType[]
Unhandled exception. System.ArrayTypeMismatchException: Attempted to access an element as a type incompatible with the array.
at Program.<Main>$(String[] args) in /home/smdn/temp/GetGenericArgumentsAsSpan/Program.cs:line 18
Regression?
No response
Known Workarounds
If a strict Type[] is required, the array must be re-created using Cast<Type>().ToArray() or similar methods:
t.GetGenericArguments().Cast<Type>().ToArray().AsSpan();Configuration
$ dotnet --info
.NET SDK:
Version: 10.0.101
Commit: fad253f51b
Workload version: 10.0.100-manifests.1773493e
MSBuild version: 18.0.6+fad253f51
Runtime Environment:
OS Name: ubuntu
OS Version: 24.04
OS Platform: Linux
RID: ubuntu.24.04-x64
Base Path: /usr/lib/dotnet/sdk/10.0.101/
csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="10.0.2"/>
</ItemGroup>
</Project>
Other information
In the current implementation of RoType.GetGenericArguments(), the method returns a copy of the array using CloneArray():
Line 103 in b7db56a
| public override Type[] GetGenericArguments() => GetGenericArgumentsNoCopy().CloneArray(); |
Specifying Type as the explicit generic argument for CloneArray should ensure the resulting array is created as Type[] instead of preserving the original RoType[] type.
This change may resolve the issue (I haven't actually verified if it works):
// Don't seal since we may need to convert any modified types to unmodified.
- public override Type[] GetGenericArguments() => GetGenericArgumentsNoCopy().CloneArray();
+ public override Type[] GetGenericArguments() => GetGenericArgumentsNoCopy().CloneArray<Type>();