Skip to content

Instantly share code, notes, and snippets.

@aabs
Created July 23, 2017 21:42
Show Gist options
  • Save aabs/ec936dd21a1e823fcef2e0b6e4110eb0 to your computer and use it in GitHub Desktop.
Save aabs/ec936dd21a1e823fcef2e0b6e4110eb0 to your computer and use it in GitHub Desktop.
Functional IO Dependency Wrapping
// Use delegates to provide a nice clean name for complex func types
public delegate bool FileExists(string path);
public delegate byte[] ReadContent(string path);
public delegate void WriteContent(string path, byte[] content);
// this is the original function looked at, which contains two accesses of the filesystem,
// which had been intercepted through the use of System.IO.Abstractions
public byte[] GetContent(string path)
{
if (path == null) { throw new ArgumentNullException(nameof(path)); }
if (!_fileSystem.File.Exists(path))
{
throw new FileNotFoundException();
}
return _fileSystem.File.ReadAllBytes(path);
}
// First extract the external dependencies as functions and pass them in as args
public static byte[] GetContent(string path, Func<string, bool> exists, Func<string, byte[]> read)
{
if (path == null) { throw new ArgumentNullException(nameof(path)); }
if (!exists(path))
{
throw new FileNotFoundException();
}
return read(path);
}
// Now change the original function itself to return a functon
// this allows the function to be partially invoked with the dependencies and than passed in to
// some other client to be used.
// NB: Note the use of the same delegate for the result as for the arg, indicating the function acting as a kind of 'pass-through'
// which does capture aspects of the implementation somewhat.
public static ReadContent GetContent2(FileExists exists, ReadContent read) => (string path) =>
{
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}
if (!exists(path))
{
throw new FileNotFoundException();
}
return read(path);
};
[UnitTest]
public static void TestCase()
{
// just pass in a couple of dummy functions to mock the interactions with the filesystem
var t = GetContent2(x => true, y => new byte[] { });
var result = t("blah");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment