File to CSharp Const

I was getting tired how many times I am reading from embedded resources – and finding it over and over the same code. So – what if I will transform the file into C# text ? Seems a work for Roslyn Source Code Generator – and the new one

IIncrementalGenerator

https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.md  , not the old ISourceGenerator https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview

So the code reads from additional files defined in .csproj

<ItemGroup>
<AdditionalFiles Include=”Second.gen.txt” />
<AdditionalFiles Include=”first.gen.txt” />
<AdditionalFiles Include=”test\Afirst.gen.txt” />
< /ItemGroup>

and then transforms in a const:

string x= MyAdditionalFiles.Second_gen_txt;

Now, how difficult is the code?

The first version was

public void Initialize(IncrementalGeneratorInitializationContext initContext)
{
IncrementalValuesProvider<AdditionalText> textFiles = initContext
    .AdditionalTextsProvider
    .Where(file => file.Path.Contains(".gen."));

// read their contents and save their name
IncrementalValuesProvider<(string name, string content)> namesAndContents = textFiles
    .Select((text, cancellationToken) => (name: Path.GetFileName(text.Path), content: text.GetText(cancellationToken)!.ToString()));
            
// generate a class that contains their values as const strings
initContext.RegisterSourceOutput(namesAndContents, (spc, nameAndContent) =>
{
                
    string nameString=nameAndContent.name
        .Replace(".","_")
        .Replace("-", "_")
        ;
        
    string[] lines = nameAndContent.content
        .Split('\n', '\r')
        .Where(it => it.Trim().Length > 0)
        .Select(it => it.Replace("\\", "\\\\"))
        .Select(it => it.Replace("\"", "\\\""))
        .Select(it => "\"" + it + "\\r\\n" + "\"")
        .ToArray();
    string content = string.Join("\r\n+", lines);
    string hint = $"MyAdditionalFiles.{nameAndContent.name}";
    var str = $@"
public static partial class MyAdditionalFiles
{{
//https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/raw-string                
public const string {nameString} =  {content};
}}";
    spc.AddSource(hint,str );
});
}

But it have performed poorly ( 3 minutes build for a file with 2MB ) . I was thinking that splitting into lines and replacing quotes and / was the faulty

So raw strings, https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/raw-string , to the help – the second version is

//v1
//string[] lines = nameAndContent.content
//    .Split('\n', '\r')
//    .Where(it => it.Trim().Length > 0)
//    .Select(it => it.Replace("\\","\\\\"))
//    .Select(it=>it.Replace("\"","\\\""))
//    .Select(it => "\"" + it +"\\r\\n"+ "\"")
//    .ToArray();
//string content = string.Join("\r\n+",lines);
//v2 => .net 7
string content=nameAndContent.content;       
//too much, but otherwise start counting quotes
var quotes = new string('"', 10);
content = quotes+"\r\n"+ content+"\r\n"+ quotes;

 

Additional details to be mentioned:

1.The Release with GitHUb Actions should also to be mentioned –the deployment to NUGET is a easy way now

2. Debugging is relative easy https://github.com/JoanComasFdz/dotnet-how-to-debug-source-generator-vs2022

3. It is a day of work to get rid of embedded files!

4. Does not work with binary files ( error with AdditionalFiles )

You can find the package at https://github.com/ignatandrei/RSCG_Utils .