Champion issue: #8617
Add #:
directive prefix to be used by tooling, but ignored by the language.
#!/usr/bin/dotnet run
#:sdk Microsoft.NET.Sdk.Web
#:property TargetFramework net11.0
#:property LangVersion preview
#:package System.CommandLine 2.0.0-*
Console.WriteLine("Hello, World!");
We are adding dotnet run file.cs
support in .NET SDK.
Real-world file-based programs need to reference NuGet packages.
It would be also useful if it were possible to execute file-based programs directly like ./file.cs
when they have the shebang directive (#!
).
The language should ignore these directives, but compiler implementations and other tooling can recognize them. We already have similar directives in the language:
#region
#pragma
: details are implementation specific#error version
: theversion
part is not in the spec, but Roslyn will report its version
Introduce new ignored pre-processing directives (§6.5):
PP_Kind
: ... // Existing directive kinds
| PP_Ignored
;
PP_Ignored
: PP_IgnoredToken Input_Character*
;
PP_IgnoredToken
: '!'
| ':'
;
Ignored directives must occur before the first token (§6.4) in the compilation unit, just like #define
/#undef
directives.
This improves readability (all package references and other configuration is in one place), tooling performance (no need to scan long files in full).
Ignored directives must also occur before any #if
directives because the tooling might not know the full set of conditional compilation symbols while parsing ignored directives.
Furthermore, the compiler should report a warning if the #!
directive is not placed at the first line and the first character in the file
(not even a BOM marker can be in front of it), because otherwise shells won't recognize it.
Compilers are also free to report errors if these directives are used in unsupported scenarios,
e.g., Roslyn will report an error if these directives are present in a file compiled as part of "project-based programs" as opposed to "file-based programs"
(and tooling will remove these directives when migrating file-based programs to project-based programs).
That error should not be reported for the #!
directive, it can be placed on any file because it might invoke some other tool than dotnet run
.
Similarly, the compiler or SDK should still error/warn on unrecognized directives to "reserve" them for future use by the official .NET tooling.
We could add each ignored directive to the language instead of introducing one ignored prefix.
- For
dotnet run file.cs
specifically, we might want to add only as few directives as possible, and for anything more advanced, recommend users to eject to project-based programs instead (i.e., avoid having two ways to configure everything). - In any case, it might be good if new directives are discussed and approved by the language design team since they are part of the overall C# language experience.
#!/usr/bin/dotnet run
#sdk Microsoft.NET.Sdk.Web
#property TargetFramework net11.0
#property LangVersion preview
#package System.CommandLine 2.0.0-*
#something // unrecognized directives would still be required by the language spec to be an error
Console.WriteLine("Hello, World!");
Other syntax forms could be used except for shebang which shells recognize only by #!
.
We could reuse #pragma
directive although that's originally meant for compiler options, not SDK (project-wide) options.
#pragma package Microsoft.CodeAnalysis 4.14.0
We could introduce only a single new directive for everything (packages, sdks, and possibly more in the future).
For example, #r
is already supported by C# scripting and other existing tooling.
However, the naming of the directive is less clear.
#r "nuget: Microsoft.CodeAnalysis, 4.14.0"
We could reserve another sigil prefix (e.g., #!
/#@
/#$
) for any directives that should be ignored by the language.
Note that #!
would be interpreted as shebang by shells if it is at the first line of the file.
#!/usr/bin/dotnet run
##package Microsoft.CodeAnalysis 4.14.0
We could use comments instead of introducing new directives.
Reusing normal comments with //#
might be confused with directives that have been commented out unless we use some other syntax like //!
but both of these could be breaking.
Documentation XML comments are more verbose and we would need to ensure they do not apply to the class below them when placed at the top of the file.
//#package Microsoft.CodeAnalysis 4.14.0
/// <package name="Microsoft.CodeAnalysis" version="4.14.0" />