File system manipulation helper What do you think about this file system manipulation helper? There is an utility class Folder which I can use to define directory structure of my app:

static class Folders
{
    public static Folder Bin =&gt;
        new Folder(Assembly.GetExecutingAssembly());

    public static Folder App =&gt; Bin.Up();
    public static Folder Docs =&gt; App.Down("Docs");
    public static Folder Temp =&gt; App.Down("Temp");
}


Then I can do some manipulations in an easy way:

    static void Main(string[] args)
    {
        Folders.Temp.Create();
        Folders.Bin.Run("scan.exe.", "-no-ui");
        Folders.Temp.CopyTo(Folders.Docs, f =&gt; f.EndsWith(".pdf"));
        Folders.Temp.Empty();
    }


Here is the library class Folder used above:

public class Folder
{
    readonly string _path;

    public Folder(Assembly assembly) 
        : this(Path.GetDirectoryName(assembly.Location))
    {
    }

    public Folder(string path)
    {
        _path = path;
    }

    public override string ToString() =&gt; _path;

    public static implicit operator string(Folder folder) =&gt;
        folder.ToString();

    public IEnumerable&lt;Folder&gt; Folders =&gt;
        Directory.GetDirectories(this, "*", SearchOption.TopDirectoryOnly)
            .Select(p =&gt; new Folder(p));

    public IEnumerable&lt;Folder&gt; AllFolders =&gt;
        Directory.GetDirectories(this, "*", SearchOption.AllDirectories)
            .Select(p =&gt; new Folder(p));

    public IEnumerable&lt;string&gt; Files =&gt;
        Directory.GetFiles(this, "*.*", SearchOption.TopDirectoryOnly);

    public IEnumerable&lt;string&gt; AllFiles =&gt;
        Directory.GetFiles(this, "*.*", SearchOption.AllDirectories);

    public Folder Up() =&gt;
        new Folder(
            new DirectoryInfo(this)
                .Parent.FullName);

    public Folder Down(string folderName) =&gt;
        new Folder(
            Path.Combine(
                this,
                folderName));

    public void Create() =&gt;
        Directory.CreateDirectory(this);

    public void Empty()
    {
        var directoryInfo = new DirectoryInfo(this);
        if (!directoryInfo.Exists)
            return;

        foreach (var file in AllFiles)
            File.Delete(file);

        foreach (var folder in Folders)
            Directory.Delete(folder, true);
    }

    public void CopyTo(Folder destination) =&gt;
        CopyTo(destination, file =&gt; true);

    public void CopyTo(Folder destination, Func&lt;string, bool&gt; filter)
    {
        //Create directories
        foreach (string directoryPath in AllFolders)
            Directory.CreateDirectory(directoryPath.Replace(this, destination));

        //Copy all the files &amp; replaces any files with the same name
        foreach (string filePath in AllFiles.Where(filter))
            File.Copy(filePath, filePath.Replace(this, destination), true);
    }

    public void Run(string exe, string args = "")
    {
        string defaultCurrentDirectory = Environment.CurrentDirectory;
        Environment.CurrentDirectory = this;
        try
        {
            var process = new Process();
            process.StartInfo.FileName = exe;
            process.StartInfo.Arguments = args;
            process.Start();
            process.WaitForExit();
            if (process.ExitCode != 0)
                throw new InvalidOperationException(
                    $"{exe} process failed with exit code {process.ExitCode}.");
        }
        finally
        {
            Environment.CurrentDirectory = defaultCurrentDirectory;
        }
    }
}
I'm always a fan of using interfaces wherever possible so that unit tests can mock out my component easily. So let's create a couple of interfaces:

public interface IFolder
{
    IEnumerable&lt;IFolder&gt; Folders { get; }

    IEnumerable&lt;IFolder&gt; AllFolders { get; }

    IEnumerable&lt;string&gt; Files { get; }

    IEnumerable&lt;string&gt; AllFiles { get; }

    IFolder Up();

    IFolder Down(string folderName);

    void Create();

    void Empty();

    void CopyTo(IFolder destination);

    void CopyTo(IFolder destination, Func&lt;string, bool&gt; filter);

    void Run(string exe, string args = "");
}


and

internal interface IFolders
{
    IFolder Bin { get; }

    IFolder App { get; }

    IFolder Docs { get; }

    IFolder Temp { get; }
}


I also like to re-use constants. And I added another implicit operator to go with your new constructor:

public class Folder : IFolder
{
    private const string DirectoryWildcard = "*";

    private const string FileWildcard = "*.*";

    private readonly string _Path;

    public Folder(Assembly assembly)
        : this(Path.GetDirectoryName(assembly.Location))
    {
    }

    public Folder(string path)
    {
        this._Path = path;
    }

    public override string ToString() =&gt; this._Path;

    public static implicit operator string(Folder folder) =&gt; folder.ToString();

    public static implicit operator Folder(string path) =&gt; new Folder(path);

    public static implicit operator Folder(Assembly assembly) =&gt; new Folder(assembly);

    public IEnumerable&lt;IFolder&gt; Folders =&gt; Directory
        .GetDirectories(this, DirectoryWildcard, SearchOption.TopDirectoryOnly)
        .Select(path =&gt; new Folder(path));

    public IEnumerable&lt;IFolder&gt; AllFolders =&gt; Directory
        .GetDirectories(this, DirectoryWildcard, SearchOption.AllDirectories)
        .Select(path =&gt; new Folder(path));

    public IEnumerable&lt;string&gt; Files =&gt; Directory.GetFiles(this, FileWildcard, SearchOption.TopDirectoryOnly);

    public IEnumerable&lt;string&gt; AllFiles =&gt; Directory.GetFiles(this, FileWildcard, SearchOption.AllDirectories);

    public IFolder Up() =&gt; new Folder(new DirectoryInfo(this).Parent.FullName);

    public IFolder Down(string folderName) =&gt; new Folder(Path.Combine(this, folderName));

    public void Create() =&gt; Directory.CreateDirectory(this);

    public void Empty()
    {
        var directoryInfo = new DirectoryInfo(this);

        if (!directoryInfo.Exists)
        {
            return;
        }

        foreach (var file in AllFiles)
        {
            File.Delete(file);
        }

        foreach (var folder in Folders)
        {
            Directory.Delete(folder.ToString(), true);
        }
    }

    public void CopyTo(IFolder destination) =&gt; this.CopyTo(destination, file =&gt; true);

    public void CopyTo(IFolder destination, Func&lt;string, bool&gt; filter)
    {
        // Create directories
        foreach (var folder in this.AllFolders)
        {
            Directory.CreateDirectory(folder.ToString().Replace(this, destination.ToString()));
        }

        // Copy all the files &amp; replaces any files with the same name
        foreach (var filePath in this.AllFiles.Where(filter))
        {
            File.Copy(filePath, filePath.Replace(this, destination.ToString()), true);
        }
    }

    public void Run(string exe, string args = "")
    {
        var defaultCurrentDirectory = Environment.CurrentDirectory;

        Environment.CurrentDirectory = this;
        try
        {
            var process = new Process { StartInfo = { FileName = exe, Arguments = args } };

            process.Start();
            process.WaitForExit();
            if (process.ExitCode != 0)
            {
                throw new InvalidOperationException(
                    $"{exe} process failed with exit code {process.ExitCode}.");
            }
        }
        finally
        {
            Environment.CurrentDirectory = defaultCurrentDirectory;
        }
    }
}


And finally, the Folders.cs implementation:

internal class Folders : IFolders
{
    private readonly Assembly _Assembly;

    public Folders(Assembly assembly = null)
    {
        this._Assembly = assembly ?? Assembly.GetExecutingAssembly();
    }

    public static IFolders Default =&gt; new Folders();

    public IFolder Bin =&gt; new Folder(this._Assembly);

    public IFolder App =&gt; this.Bin.Up();

    public IFolder Docs =&gt; this.App.Down("Docs");

    public IFolder Temp =&gt; this.App.Down("Temp");
}


Now that it's not static, you'll either have to create a new one with a particular assembly, or Folders.Default will have the current assembly as per original design.