DIVEX

Inject operators

The Inject operator allows you to inject a function as a value for a parameter (of type function) of another function. Such injection works even if the injected function has more parameters. Consider this example:

[DivexCompose]
public static partial class Program
{
    public record Document(string Content, string Name);

    static void Main(string[] args)
    {
        DelFunc.DF1 postContentToWebService = (Document document, HttpClient httpClient, Uri uri) =>
        {
            httpClient.PostAsync(
                uri,
                new StringContent(document.Content))
                .Result.EnsureSuccessStatusCode();
        };

        DelFunc.DF2 readAndProcess = (string folderPath, Action<Document> process) =>
        {
            foreach(var filePath in Directory.GetFiles(folderPath))
            {
                var document = new Document(File.ReadAllText(filePath), Path.GetFileName(filePath));

                process(document);
            }
        };

        var processFolder = readAndProcess
            .Inject(process: postContentToWebService);
                

        processFolder.Invoke(
            folderPath: @"C:\Documents",
            httpClient: new HttpClient(),
            uri: new Uri("https://local.lab/Document"));
    }
}
DelFunc.DF1 and DelFunc.DF2 are Delegate Functions. Delegate Functions is a way to support treating lambdas as functions.

In the above example, the process parameter in readAndProcess is of type Action<Document>. That is, it is a function that takes a Document and returns nothing. Using the Inject operator, the postContentToWebService function was injected as a value of this parameter. This is possible in spite of the fact that postContentToWebService has two additional parameters: httpClient and uri. These parameters are bubbled up to the resulting function, the processFolder function.

The InjectOne and InjectLast operators are similar to the Inject operator. They work when the parameter we are injecting into is an array (or ImmutableArray<T>). Consider this example:

[DivexCompose]
public static partial class Program
{
    public record Document(string Content, string Name);

    static void Main(string[] args)
    {
        DelFunc.DF1 processMultiple = (Document document, Action<Document>[] processors) =>
        {
            foreach (var process in processors)
            {
                process(document);
            }
        };

        DelFunc.DF3 writeContentToConsole = (Document document) => Console.WriteLine(document.Content);

        DelFunc.DF4 postContentToWebService = (Document document, HttpClient httpClient, Uri uri) =>
        {
            httpClient.PostAsync(
                uri,
                new StringContent(document.Content))
                .Result.EnsureSuccessStatusCode();
        };

        DelFunc.DF2 readAndProcess = (string folderPath, Action<Document> process) =>
        {
            foreach(var filePath in Directory.GetFiles(folderPath))
            {
                var document = new Document(File.ReadAllText(filePath), Path.GetFileName(filePath));

                process(document);
            }
        };

        var processDocument = processMultiple
            .InjectOne(processors: writeContentToConsole)
            .InjectLast(processors: postContentToWebService)
            .Apply(uri: new Uri("https://test.lab/document"))
            .Apply(httpClient: new HttpClient());

        processDocument.Invoke(new Document("Sample content", "Sample name"));
    }
}

The processMultiple function has a parameter named processors of type Action<Document>[]. processMultiple is an implementation of the Composite pattern. InjectOne and InjectLast were used to inject two functions (writeContentToConsole and postContentToWebService) as a value for the processors parameter. InjectOne injects a function as a value for one element in the array. The function resulting from using InjectOne will have a parameter called processors. This enables us to use InjectOne for as many times as we want to inject more functions into the array. The last function to inject into the array must be injected using InjectLast so that the array parameter is removed from the resulting function.