Skip to content

ReflectionTypeLoadException when static field of readonly record struct references other struct #121577

@Sebazzz

Description

@Sebazzz

Description

Note: this is fixed in .NET 10 bug exists in .NET 8.0.415 and .NET 9.0.307

When a readonly record struct static field references another readonly record struct the types won't load and a ReflectionTypeLoadException is thrown when attempting to use Assembly.GetTypes.

Reproduction Steps

Files and contents:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework><!-- or net8.0 -->
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Listing types in current assembly:");

foreach (var type in typeof(Program).Assembly.GetTypes())
{
    Console.WriteLine(type.FullName);
}
namespace TypeLoadBug;

internal readonly record struct QuestionTrigger(string QuestionId, int AnswerId) {
    public static readonly QuestionTriggerList NoTriggers = default;
}

internal readonly record struct QuestionTriggerList(QuestionTrigger Trigger1, QuestionTrigger Trigger2, QuestionTrigger Trigger3) : IEnumerable<QuestionTrigger> {
    public IEnumerator<QuestionTrigger> GetEnumerator() {
        if (this.Trigger1 != default) yield return this.Trigger1;
        if (this.Trigger2 != default) yield return this.Trigger2;
        if (this.Trigger3 != default) yield return this.Trigger3;
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => this.GetEnumerator();
    
    public static QuestionTriggerList Create((string? QuestionId, int? AnswerId) trigger1, (string? QuestionId, int? AnswerId) trigger2, (string? QuestionId, int? AnswerId) trigger3) {
        return new QuestionTriggerList(
            trigger1.QuestionId is not null && trigger1.AnswerId is not null ? new QuestionTrigger(trigger1.QuestionId, trigger1.AnswerId.Value) : default,
            trigger2.QuestionId is not null && trigger2.AnswerId is not null ? new QuestionTrigger(trigger2.QuestionId, trigger2.AnswerId.Value) : default,
            trigger3.QuestionId is not null && trigger3.AnswerId is not null ? new QuestionTrigger(trigger3.QuestionId, trigger3.AnswerId.Value) : default
        );
    }
    
}

Expected behavior

Output:

Listing types in current assembly:
Program
TypeLoadBug.QuestionTrigger
TypeLoadBug.QuestionTriggerList
TypeLoadBug.QuestionTriggerList+<GetEnumerator>d__13

Actual behavior

Output:

Listing types in current assembly:
Unhandled exception. System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types.
Could not load type 'TypeLoadBug.QuestionTrigger' from assembly 'TypeLoadBug, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
Could not load type 'TypeLoadBug.QuestionTriggerList' from assembly 'TypeLoadBug, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
Could not load type 'TypeLoadBug.QuestionTrigger' from assembly 'TypeLoadBug, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
   at System.Reflection.RuntimeModule.GetDefinedTypes()
   at System.Reflection.RuntimeModule.GetTypes()
   at Program.<Main>$(String[] args) in D:\ProjectsTemp\TypeLoadBug\Program.cs:line 4
System.TypeLoadException: Could not load type 'TypeLoadBug.QuestionTrigger' from assembly 'TypeLoadBug, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
System.TypeLoadException: Could not load type 'TypeLoadBug.QuestionTriggerList' from assembly 'TypeLoadBug, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
System.TypeLoadException: Could not load type 'TypeLoadBug.QuestionTrigger' from assembly 'TypeLoadBug, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
                                  

Regression?

Unknown

Known Workarounds

Move the static readonly field to the struct of its type.

Configuration

.NET on Windows, happens on 8.0.415 and 9.0.307 SDKs

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions