Skip to content

[net11p3] Razor SG emits synthetic members with empty names for switch expressions returning RenderFragment lambdas with inline markup #13117

Description

@davidortinau

Summary

The Razor source generator in .NET 11 Preview 3 (11.0.100-preview.3.26209.122) emits synthetic members with empty identifier names when a .razor file contains a switch expression that returns RenderFragment lambdas with inline Razor markup. This produces CS0101/CS0102 errors with empty '' names, and the resulting failure cascades through the rest of the file — CS0246 for every type referenced (including @inject services and inline-defined enums) and, in larger files with multiple @inject directives, a swarm of CS9348: The compilation unit cannot directly contain members.

The same code compiles cleanly under .NET 10 GA.

Repro

dotnet new maui-blazor, add the following file:

Pages/RazorSgRepro.razor

@page "/repro"
@inject NavigationManager Nav

<PageTitle>RazorSgRepro</PageTitle>

<h1>Razor SG Regression Repro</h1>

<div>@RenderBadge(SampleType.Alpha)</div>
<div>@RenderBadge(SampleType.Beta)</div>
<div>@RenderBadge(SampleType.Gamma)</div>

@code {
    public enum SampleType { Alpha, Beta, Gamma }

    private static RenderFragment RenderBadge(SampleType type) => type switch
    {
        SampleType.Alpha => (__builder) =>
        {
            <span class="badge bg-primary"><i class="bi bi-fonts me-1"></i>Alpha</span>
        },
        SampleType.Beta => (__builder) =>
        {
            <span class="badge bg-secondary"><i class="bi bi-chat-quote me-1"></i>Beta</span>
        },
        _ => (__builder) =>
        {
            <span class="badge bg-light">Unknown</span>
        }
    };
}

Pin the SDK via global.json:

{ "sdk": { "version": "11.0.100-preview.3.26209.122", "rollForward": "latestFeature", "allowPrerelease": true } }

Then:

dotnet clean && rm -rf */obj */bin
dotnet build

A complete minimal solution (zipped) is attached below as peethree-net11p3-repro.zip.

Expected

Build succeeds, as it does under .NET 10 GA.

Actual

Build fails with the following error fingerprint:

Pages/RazorSgRepro.razor(23,54): error CS0101: The namespace '...Pages' already contains a definition for ''
Pages/RazorSgRepro.razor(19,52): error CS0102: The type 'RazorSgRepro'   already contains a definition for ''
Pages/RazorSgRepro.razor(2,9):  error CS0246: The type or namespace name 'NavigationManager' could not be found
Pages/RazorSgRepro.razor(21,9): error CS0246: The type or namespace name 'SampleType' could not be found

The diagnostic signature — CS0101 / CS0102 reporting duplicate definitions with EMPTY names — points squarely at the Razor SG: it is synthesizing the per-arm RenderFragment member without assigning a stable identifier when the lambda body contains inline Razor markup.

In larger production files (we hit this in a 1168-line .razor page with 10 @inject directives), the SG appears to give up on the file entirely and emits the injected fields at compilation-unit scope, producing 31 errors dominated by CS9348: The compilation unit cannot directly contain members on every @inject line, plus the empty-name CS0101/CS0102 collisions and cascading CS0246 on every injected type. The minimal repro above is the smallest form that still produces the empty-name SG fingerprint.

Workaround

Either (a) extract each switch arm to a separately-named RenderFragment helper:

private static RenderFragment RenderBadge(SampleType type) => type switch
{
    SampleType.Alpha => RenderAlpha(),
    SampleType.Beta  => RenderBeta(),
    _                => RenderUnknown(),
};

private static RenderFragment RenderAlpha() => @<span class="badge bg-primary">Alpha</span>;

…or (b) replace the RenderFragment-returning helper with a tuple-returning meta helper and inline the markup at the call site:

private static (string CssClass, string Label) GetBadge(SampleType type) => type switch
{
    SampleType.Alpha => ("bg-primary",   "Alpha"),
    SampleType.Beta  => ("bg-secondary", "Beta"),
    _                => ("bg-light",     "Unknown"),
};
@{ var b = GetBadge(type); }
<span class="badge @b.CssClass">@b.Label</span>

Both workarounds compile under net11p3 and net10 GA.

Environment

  • OS: macOS 15.x (Darwin), Apple Silicon
  • SDK that fails: 11.0.100-preview.3.26209.122
  • SDK that works: 10.0.101 (.NET 10 GA)
  • Project type: dotnet new maui-blazor (MAUI Blazor Hybrid + Web), Razor SG running against the .Shared project
  • Reproduces with full clean (rm -rf */obj */bin) — not a stale cache.

Attachments

  • Build log: see body above (full log: ~3KB)
  • Minimal solution zip: peethree-net11p3-repro.zip (252KB)

peethree-net11p3-repro.zip

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions