mirror of
https://github.com/icsharpcode/ILSpy.git
synced 2026-10-12 02:15:58 +00:00
A chain of type forwarders is followed by assembly name, and every name resolves relative to the assembly being decompiled - so a chain that leaves for another framework can be pulled straight back into the directory it started in. A .NET Standard 2.0 assembly sitting among .NET Framework 4.6.1 facades lost System.Linq.Enumerable that way: the chain went netstandard -> System.Core (from the shared framework) -> System.Linq (back to the input directory) -> netstandard, arriving at an assembly it had already passed through. Nothing in the closure defines the type, so it stayed unknown and every LINQ call decompiled as a static call with a delegate cast. Once the closure is loaded, chains that return to an assembly they already visited are walked a second time, resolving each hop next to the assembly that forwards it. The assembly ending the repaired chain is loaded only once it is confirmed to declare the type; it then wins the deduplication against the assembly of the same name it displaces, which version order says nothing about. An assembly that neither forwards nor declares the type ends the walk with nothing loaded, so a failed repair cannot displace anything. Only chains that are already broken are walked twice. Preferring the forwarder's own directory as a resolution policy was tried first and rejected: measured against a corpus, it moved a .NET 8 facade's System.Runtime reference out of a net4x compilation, splitting type identities so that overrides printed as virtual. The two cases cannot be told apart where references are resolved, because that layer sees assembly names, not the type whose chain is or is not terminating. AssemblyReference now knows the module that declares it, which is what lets a hop be resolved next to its forwarder, and its metadata reader is that module's. A chain that cannot be repaired is reported in the reference load log the UI already shows, once per reference: a facade forwards hundreds of types and they all fail together. Assisted-by: Claude:claude-opus-5:Claude Code