Decompiling VB.NET-compiled assemblies that use anonymous types produces uncompilable C#: anonymous type definitions are hidden from the output, but use sites still reference them by their metadata name.
Reproduction
- NuGet package
QuartzNetWebConsole 1.0.2, assembly QuartzNetWebConsole.Views.dll (VB.NET-compiled), current master, default DecompilerSettings.
- Decompile e.g.
QuartzNetWebConsole.Views.Views (or any member using VB anonymous types / LINQ Select ... Into).
Observed
Use sites emit the raw generated names, which are not valid C#:
select new VB$AnonymousType_2<TriggerWithState, ITrigger>(tr, tr.Trigger) into $VB$It
select new VB$AnonymousType_3<VB$AnonymousType_2<TriggerWithState, ITrigger>, bool>($VB$It, ...) into $VB$It
At the same time DecompileTypeAsString(new FullTypeName("VB$AnonymousType_02"))` yields an empty string, i.e. the definition is suppressed, so the emitted code has no declaration to fall back on.
Analysis
Two generated-name predicates disagree about VB names:
SRMExtensions.IsGeneratedName treats names containing $ as generated, and SRMExtensions.IsAnonymousType therefore matches VB$AnonymousType_*. This is what CSharpDecompiler.MemberIsHidden uses (CSharpDecompiler.cs:389), so the definitions are hidden when settings.AnonymousTypes is on.
NRExtensions.HasGeneratedName(IType) only matches names starting with/containing <, so the type-system-level NRExtensions.IsAnonymousType(IType) returns false for VB$AnonymousType_*. As a result none of the anonymous-type translation paths in CallBuilder/ExpressionBuilder (e.g. CallBuilder.cs:1412/1838) fire for VB assemblies, and no new { ... } is synthesized.
Aligning NRExtensions.IsAnonymousType/HasGeneratedName with the SRM-level predicate should make VB anonymous types round-trip like the C# ones (<>f__AnonymousType*).
Related, likely a separate work item: VB also emits VB$AnonymousDelegate_* types (visible in the first snippet's generic arguments). C# has no equivalent construct, so those would additionally need mapping to Func<...>/Action<...> or a synthesized named delegate to make the output compilable.
This issue was written by an AI agent (Claude) on Siegfried's behalf.
Decompiling VB.NET-compiled assemblies that use anonymous types produces uncompilable C#: anonymous type definitions are hidden from the output, but use sites still reference them by their metadata name.
Reproduction
QuartzNetWebConsole1.0.2, assemblyQuartzNetWebConsole.Views.dll(VB.NET-compiled), current master, defaultDecompilerSettings.QuartzNetWebConsole.Views.Views(or any member using VB anonymous types / LINQSelect ... Into).Observed
Use sites emit the raw generated names, which are not valid C#:
At the same time
DecompileTypeAsString(new FullTypeName("VB$AnonymousType_02"))` yields an empty string, i.e. the definition is suppressed, so the emitted code has no declaration to fall back on.Analysis
Two generated-name predicates disagree about VB names:
SRMExtensions.IsGeneratedNametreats names containing$as generated, andSRMExtensions.IsAnonymousTypetherefore matchesVB$AnonymousType_*. This is whatCSharpDecompiler.MemberIsHiddenuses (CSharpDecompiler.cs:389), so the definitions are hidden whensettings.AnonymousTypesis on.NRExtensions.HasGeneratedName(IType)only matches names starting with/containing<, so the type-system-levelNRExtensions.IsAnonymousType(IType)returns false forVB$AnonymousType_*. As a result none of the anonymous-type translation paths inCallBuilder/ExpressionBuilder(e.g. CallBuilder.cs:1412/1838) fire for VB assemblies, and nonew { ... }is synthesized.Aligning
NRExtensions.IsAnonymousType/HasGeneratedNamewith the SRM-level predicate should make VB anonymous types round-trip like the C# ones (<>f__AnonymousType*).Related, likely a separate work item: VB also emits
VB$AnonymousDelegate_*types (visible in the first snippet's generic arguments). C# has no equivalent construct, so those would additionally need mapping toFunc<...>/Action<...>or a synthesized named delegate to make the output compilable.This issue was written by an AI agent (Claude) on Siegfried's behalf.