Improve duplicate #:include handling for file-based C# apps by deduplicating compile inputs
- 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.