dotnet / dotnet/sdk

Improve duplicate #:include handling for file-based C# apps by deduplicating compile inputs

Open
#54,080 3 comments 0 reactions 0 assignees View on GitHub
Area-run-file untriaged
Dominant language
C#
Stars
3.2k
Forks
1.3k
PR merge metrics
PR metrics pending

Description

### Is your feature request related to a problem? Please describe.

I'm trying to use `#:include` to compose modular file-based C# apps, but duplicate inclusion through transitive include graphs currently produces a poor experience.

A simple example is:

- A includes B
- B includes C
- A also includes C

In this scenario, the app can still build and run successfully, but the build emits `CS2002` because the same source file is passed to the compiler multiple times.

From a file-based app user's perspective, this is not really the same as accidentally invoking the compiler with the same source file twice. It is a natural outcome of source composition through `#:include`.

Requiring users to manually pre-deduplicate include graphs makes file-based apps less elegant and pushes them toward heavier project-style preprocessing, which works against the lightweight promise of the feature.

Related discussions / implementations:
- [`dotnet/sdk#52347`](https://github.com/dotnet/sdk/pull/52347) — added `#:include` support for file-based apps
- [`dotnet/roslyn#82625`](https://github.com/dotnet/roslyn/pull/82625) — editor completion support for `#:include`
- discussion about declarative conditional directives: [`dotnet/sdk#52532`](https://github.com/dotnet/sdk/issues/52532#issuecomment-4325233839)

### Describe the solution you'd like

I'd like the SDK to recognize file-based app include graphs and **deduplicate repeated source files before passing compile inputs to the compiler**.

Preferred behavior:

- detect duplicate source files arising from `#:include` expansion
- normalize / resolve paths first
- compile each source file only once
- preserve stable ordering for the first occurrence
- keep build/run/convert behavior consistent

If possible, I think this should be handled at the SDK / virtual project layer rather than being left to the compiler to surface as a raw `CS2002` experience.

If deduplication cannot be implemented immediately, an intermediate improvement would be to provide a more file-based-app-specific, lower-noise diagnostic instead of exposing the traditional duplicate-source warning experience directly.

Alternative solutions considered:

- leaving the current behavior as-is and expecting users to manually deduplicate include closures
- works, but does not feel appropriate for a lightweight file-based app model
- lowering the severity or contextualizing the diagnostic for file-based app scenarios
- better than today, but still less ideal than SDK-side deduplication
- runtime conditional inclusion
- not recommended; build-time declarative conditions would be a better direction for advanced composition than runtime compilation behavior

### Additional context

This seems especially important if `#:include` is expected to scale beyond very small examples.

Without SDK-side deduplication, users are incentivized to add more manual preprocessing and scenario-specific closure management just to avoid duplicate include requests. That may be acceptable in specialized tooling, but it does not seem like the right default burden for typical file-based app users.

The reason I believe `dotnet/sdk` is the right place for this is that `#:include` itself appears to be implemented as an SDK / virtual-project feature ([`dotnet/sdk#52347`](https://github.com/dotnet/sdk/pull/52347)), while Roslyn support such as editor completion is handled separately ([`dotnet/roslyn#82625`](https://github.com/dotnet/roslyn/pull/82625)).

If helpful, I can provide a minimal repro based on a file-based app where transitive `#:include` causes `CS2002` even though the app still builds and runs successfully.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.