我有一个包含32个项目的Visual Studio 2023解决方案.这些项目相互广泛参考.其中31个项目是类库,而最后一个项目是一个控制台应用程序,每当我想测试我的库中的一个函数时,就会使用它,所以我不必每次都创建新的临时函数.即使在这个问题之前,Visual Studio的即时窗口对我来说也从未起过作用.所有的项目都是用C#11编写的,并使用.NET 7.0.许多项目都引用了NuGet Package System.Collections.Immutable.

我试图写一个Crawler,就像Web Crawler一样,但针对的是类型.它将迭代类型的所有静态/非静态成员,添加它们的参数类型,并将类型(如果存在)返回给HashSet<Type>.然后,它将递归地为添加的每个类型执行相同的操作.它被设计成每次只迭代一次.

它通过创建List<Type>来做到这一点,每次向HashSet<Type>添加一个尚不存在的类型时,它都会将其添加到列表中.在列表完成之后,它将递归地为列表中的每种类型执行相同的操作.如果类型是泛型参数或包含在其泛型参数中(如果存在),则它将为substituted with its definition.还有一些函数用于覆盖指针、引用和array.

我在object上运行了这个功能,它运行得很好.我使用C#的S typeof(?)方法获得了对象的类型.然而,然后我在我的一个项目中的静态类上运行了该函数,它抛出了一个异常.

在这一点上,值得一提的是与此相关的项目.我有一个控制台应用程序项目(Test),其中我正在执行第二个项目(Brendan.IC.Typed.Execution)中的爬行器,该爬行器应该爬行通过第三个项目(Brendan.IC.Typed)中的静态类.后一个项目引用了System.Collections.Immutable个.System.Collections.Immutable很可能与此无关,但我认为所有事情都值得一提,因为我完全不知道问题出在哪里.

唯一的例外是System.TypeLoadException.

System.TypeLoadException:‘无法从程序集’Brendan.IC.Typed,Version=1.0.0.0,区域性=中立,PublicKeyToken=NULL‘加载类型’Brendan.IC.Typed.TypedEvolutionLookup`1‘.’

我调用爬行器的静态类是Brendan.IC.Typed.TypedEvolution.它的一个静态方法包含类型为Brendan.IC.Typed.TypedEvolutionLookup<>的参数.爬行者就是这样找到它的.然后,它无法加载它.异常是在MethodInfo.GetParameters()函数中引发的.

起初,我以为这是我的爬虫功能出现了一些问题.我清理并重新生成了解决方案,这是我处理错误的正常第一步,但没有效果.我在DebugRelease模式下多次重新编译了解决方案,但都没有效果.我判断了代码中是否有任何可能影响类型加载的内容.我什么也没找到.最后,我决定在我的 top-level 中加载有问题的类型.它抛出了一个异常,与之前的异常相同.

System.TypeLoadException:‘无法从程序集’Brendan.IC.Typed,Version=1.0.0.0,区域性=中性,‘CodeInterpretation.Typed.TypedEvolutionLookup`1’=NULL‘加载类型密钥.’

以下是我的最高层声明:

using Brendan.IC.Typed;
using Brendan.IC.Typed.Execution;
using static System.Console;
Type bigType = typeof(TypedEvolutionLookup<int>);
Crawler.Crawl(bigType);
ReadKey(true);

我把它简化为:

using Brendan.IC.Typed;
using static System.Console;
Type bigType = typeof(TypedEvolutionLookup<int>);
ReadKey(true);

就在这时,事情开始变得奇怪起来.真的很奇怪.

首先,我注意到没有与异常相关联的行号或调用堆栈.

A picture of the exception.

Select 显示调用堆栈后:

A picture of the call stack.

这是我的全屏:

A fullscreen screenshot of the exception.

通常,当我收到异常时,我可以在我怀疑的行前添加一个WriteLine(),它将在程序因异常而终止之前打印到控制台.我这样做了,并在同一行上添加了断点,打算逐步执行该程序.最后,我向泛型类型定义添加了一个泛型参数.但是程序甚至没有命中断点!它也没有打印到控制台上!

新代码:

using Brendan.IC.Typed;
using static System.Console;
WriteLine("hi");
Type bigType = typeof(TypedEvolutionLookup<int>);
ReadKey(true);

屏幕截图:

Screenshot of exception.

我也把它设为释放模式.不出所料,它没有抛出错误,因为它优化了不必要的赋值.显然,它也没有触及断点.

我go 掉了第四行,然后它就可以正常工作了.我把它加回go ,它坏了.我试着从Brendan.IC.Typed的组装中得到一个不同的型号.它运行得很好.我用另一个ReadKey(true)语句替换了WriteLine()语句.它坏了.

using Brendan.IC.Typed;
using static System.Console;
ReadKey(true);
Type bigType = typeof(TypedEvolutionLookup<int>);
ReadKey(true);

A screenshot of the error for the latter case.

我go 掉了泛型参数.没有变化:

A screenshot of the error.

让我担心的是,我认为错误不是在执行typeof语句时发生的,而是在IL的编译器中发生的!错误是在我编译它和执行 top-level 之间抛出的!我能想到的只有一件事符合这些约束,并且取决于typeof行的存在,而且它是IL运行时编译器本身!然而,C#到IL编译器可以很容易地找到该类型!

并且该错误不会在程序集中的任何其他类型中发生!不幸的是,TypedEvolutionLookup<> struct 是Brendan.IC.Typed程序集中唯一的泛型类型.但是,它不是唯一的只读 struct .不过,我已经测试了其他一些只读 struct ,它们没有相同的问题.出于某种原因,IL编译器似乎挑出了这一特定类型,并且,无论是否依赖泛型,这种情况都不应该发生.

我已经多次重启了我的计算机,以防有一些我不知道的秘密RAM类型缓存.我已经多次清理和重新构建了解决方案,以防出现什么奇怪的情况.我已经多次删除了我所有项目的输出目录,以防一些过go 的版本与现在的版本发生冲突.

(我的所有类库都编译到相同的输出目录;但是,控制台应用程序编译到自己的目录,以避免混淆.)

没有任何变化.我不明白这一点.我想要这座建筑的System.Type英镑.为什么IL编译器要挑出这个特定的对象?它没有时髦的属性,除了它的方法的参数中偶尔有[MaybeNullWhen(false)].

为什么会发生这种情况,我又该如何避免呢?

下面是有问题的 struct 的代码:

public readonly struct TypedEvolutionLookup<TCommand>
    where TCommand : struct
{
    public TCommand? Command { get; }
    public ImmutableArray<KeyValuePair<Type, TypedEvolutionLookup<TCommand>>> OtherCommands { get; }
    public int Count { get; }
}

为简洁起见,我删除了构造函数,但它仍然生成TypeLoadException.

正如用户Dave CousineauRenat推测的那样,类型确实包含构造的泛型类型,并将其本身作为参数.如果有必要,我会补充这一点作为回答.

推荐答案

正如用户Dave CousineauRenat所确认的那样,CLR中存在一个与泛型 struct 的递归使用有关的持续错误.在Renat、herehere提供的链接中提到了该漏洞.

感谢所有帮助我的人,我希望这个问题能在future 得到解决.然而,目前情况并非如此.

Csharp相关问答推荐

List T.AddRange在传递ConcurrentDictionary作为参数时引发ArgumentExcellent

Dapper是否可以自动扩展类成员

在Dapper中使用IasyncEum重写GetAsyncEum方法

如何在Reflection. Emit中使用具有运行时定义的类型参数的泛型类型

读取配置文件(mytest. exe. config)

DbContext-传递自定义配置选项

我可以查看我们向应用程序洞察发送了多少数据吗?

如何返回具有泛型的类?

为什么我的用户界面对象移动到略低于实际目标?

Blazor:搜索框在第一次搜索时不搜索

VS代码扩展无法在新版本扩展C#中运行从v2.10.28开始

从GRPC连接创建ZipArchive

DropDownListFor未显示选定值

无法向Unity注册Microsoft Logger

在ObservableCollection上使用[NotifyPropertyChangedFor()]源代码生成器不会更新UI

实例化列表时的集合表达式是什么?

如何在C#中反序列化Java持续时间?

使用生产环境调试我的应用程序的快速方法

这是T自身的布尔表达式是什么意思?

无法停止PowerShell中的低级挂钩(c#挂钩)