A C# source generator that runs C# scripts.
-
dotnet-script tool to run C# scripts:
dotnet tool install -g dotnet-script
Info: If you don't have access to
dotnet-script
, than take a look at CSharp.SourceGen.Fsx - a C# code generator that runs F# scripts using standarddotnet fsi
command from .NET SDK.
dotnet add package Dartk.CSharp.SourceGen.Csx
To avoid propagating dependency on the package set the option PrivateAssets="all"
in the project
file:
<ItemGroup>
<PackageReference Include="Dartk.CSharp.SourceGen.Csx" Version="0.3.0" PrivateAssets="All" />
</ItemGroup>
Include C# script files with .csx extension to the project as AdditionalFiles
. For example, to execute all scripts in the Scripts folder add this to the project file:
<ItemGroup>
<AdditionalFiles Include="Scripts/**" />
</ItemGroup>
.csx script's output will be treated as a source code. Meaning that, the following script:
Console.Write("""
public static class HelloWorld
{
public const string Str = "Hello, World!";
}
""");
will generate a class:
public static class HelloWorld
{
public const string Str = "Hello, World!";
}
A complete example is presented below.
Scripts that have file names starting with an underscore will not be executed. But they can be included in other scripts using #load
statement. For instance:
- _script.csx - will not be executed, can be included in other scripts
- other-script.csx - will be executed
If a script references any other files, they should be included to the project as AdditionalFiles
as well. Because the generator is incremental, it can only cache and detect changes for "additional" files.
Warning: Microsoft Visual Studio 22 (tested on version 17.4.3 on Windows OS) will call a source generator on every edit of the files that are being cached by the generator. Thus, every character insertion or deletion in a .csx script will cause the script execution. Therefore, edit those files in an external editor for better performance.
To save the generated source files set properties EmitCompilerGeneratedFiles
and CompilerGeneratedFilesOutputPath
in the project file:
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<!--Generated files will be saved to 'obj\GeneratedFiles' folder-->
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
Create a new console C# project:
dotnet new console -n Example
Install the package Dartk.CSharp.SourceGen.Csx
and set the property PrivateAssets="All"
by editing the project file Example.csproj:
<ItemGroup>
<PackageReference Include="Dartk.CSharp.SourceGen.Csx" Version="0.3.0" PrivateAssets="All"/>
</ItemGroup>
Create a Scripts folder in the project directory and include files within as AdditionalFiles
:
<ItemGroup>
<AdditionalFiles Include="Scripts/**" />
</ItemGroup>
Add the following file to the Scripts folder:
Number.csx
#r "nuget: Scriban, 5.4.6"
using Scriban;
var template = """
namespace Generated.Csx;
public record Number(int Int, string String) {
{{- i = 0 }}
{{- for number in numbers }}
public static readonly Number {{ string.capitalize number }} = new ({{ ++i }}, "{{ number }}");
{{- end }}
}
""";
var output = Template.Parse(template).Render(new {
numbers = new [] { "one", "two", "three" }
});
Write(output);
The script above will generate source file Number.g.cs:
// Generated from 'Number.csx'
namespace Generated;
public record Number(int Int, string String) {
public static readonly Number One = new (1, "one");
public static readonly Number Two = new (2, "two");
public static readonly Number Three = new (3, "three");
}
Now Generated.Number
record can be used in your code.
Put this in the Program.cs:
using static System.Console;
WriteLine(Generated.Number.One);
WriteLine(Generated.Number.Two);
WriteLine(Generated.Number.Three);
It will write the following:
Number { Int = 1, String = one }
Number { Int = 2, String = two }
Number { Int = 3, String = three }
- CSharp.SourceGen.Fsx - Generate C# code from F# scripts
- CSharp.SourceGen.Scriban - Generate C# code from Scriban templates
- CSharp.SourceGen.Examples - Examples that demonstrate how to use
CSharp.SourceGen.*
code generators