Search code examples
c#actionpipeline

How to implement passing of parameter to a StreamedPipeline that uses Action<Stream,Stream>


I read a great article on a .Net StreamedPipeline implementation on the MSDN Magazine (https://msdn.microsoft.com/en-us/magazine/cc163290.aspx ).

I have a challenge though.

In tthe implementation, they had it call the Compress and Encrypt methods:

using (FileStream input = File.OpenRead("inputData.bin"))
using (FileStream output = File.OpenWrite("outputData.bin"))
using (StreamPipeline pipeline = new StreamPipeline(Compress, Encrypt))
{
    pipeline.Run(input, output);
}

These methods were pre-defined without any parameters other than the Stream parameters:

static void Compress(Stream input, Stream output){
    using (GZipStream compressor = new GZipStream(
           output, CompressionMode.Compress, true))
        CopyStream(input, compressor);
}

static void Encrypt(Stream input, Stream output) {
    RijndaelManaged rijndael = new RijndaelManaged();
    ... // setup crypto keys
    using (ICryptoTransform transform = rijndael.CreateEncryptor())
    using (CryptoStream encryptor = new CryptoStream(
            output, transform, CryptoStreamMode.Write))
        CopyStream(input, encryptor);
}

What I am really struggling to do is how to get other,additional, non-Stream parameters to be sent to the pipeline. e.g, if it's Encryption, I want to send the keys and have that included in the pipeline calls. How do I implement the same functionality with additional parameters?


Solution

  • You need to use the functional programming technique, partial application. Essentially you can create another anonymous function that captures your arguments and applies them to your real function.

    var additionalCompressionArgument = 123;
    using (FileStream input = File.OpenRead("inputData.bin"))
    using (FileStream output = File.OpenWrite("outputData.bin"))
    using (StreamPipeline pipeline = new StreamPipeline(
       (input, output) => Compress(input, output, additionalCompressionArgument), 
        Encrypt))
    {
        pipeline.Run(input, output);
    }
    
    static void Compress(Stream input, Stream output, int additionalCompressionParameter){
        using (GZipStream compressor = new GZipStream(
               output, CompressionMode.Compress, true))
            CopyStream(input, compressor);
    }