Suppose you wanted to generate a folder on your desktop, say to store your incomplete proposals.

A quick way to do it would be like so:

// Get the folder location
var folderLocation = $@"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\Incomplete";
Console.WriteLine(folderLocation);
// Create the folder
Directory.CreateDirectory(folderLocation);

This prints the following on my Windows environment:

C:\Users\conrada\Desktop\Incomplete

This uses the Environment.GetFolderPath to get the location of the desktop, and then you concatenate the proposed folder.

By the way, you use Environment.GetFolderPath to request the runtime to get for you the location of various system folders - don’t assume the System folder is always C:\WINDOWS\system32\ - what if the user installed Windows on Drive E? You can get a list of the folders you can retrieve here.

Fun fact: Directory.CreateDirectory does not throw an exception if the directory you want to create already exists!

There are a bunch of problems with this approach.

  1. On Windows the directory separator is \ . On MacOS and Linux is is /.
  2. String concatenation is error prone.

Is there a way the .NET can help with this problem?

Indeed.

You can use the Path.Combine method for this. This method takes two paths and, unsurprisingly, combines them.

So you change your code like so:

folderLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Incomplete");
Console.WriteLine(folderLocation);

You should get the same result.

Notice that there is no file separator specified - the runtime will know to use the current operating system separator.

What if you wanted to create a sub-folder of Incomplete?

We could do it like this:

folderLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Incomplete\Active");
Console.WriteLine(folderLocation);

This will print the following:

C:\Users\conrada\Desktop\Incomplete\Active

But we are trying to get away from specifying path separators.

For many years I would do it like this:

folderLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Incomplete");
Console.WriteLine(folderLocation);

folderLocation = Path.Combine(folderLocation, "Active");
Console.WriteLine(folderLocation);

Here we are progressively building the path by calling Path.Combine multiple times.

And then the other day a college informed me that Path.Combine has several overloads - one that takes 3 arguments, one that takes 4 arguments and one that takes a parameter array, meaning you can specify as many paths as you want.

These new overloads were introduced in .NET Framework 4.

This means that we can do this:

folderLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Incomplete", "Active", "2023", "January");
Console.WriteLine(folderLocation);

This prints out the following:

C:\Users\conrada\Desktop\Incomplete\Active\2023\January

You can combine as many paths as you want (within reason!)

A caveat is what happens when you provide complete paths as one of the arguments.

The runtime will ignore any prior complete paths and use the latest to start constructing the path.

For example:

folderLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Incomplete", "Active", @"C:\2023", "January");
Console.WriteLine(folderLocation);

This code will print the following:

C:\2023\January

The code is in my Github.

Happy hacking!