I will assume that you know how to get a list of directories (see questions like this ), so I’ll focus only on building a linq query that will sort your collection.
My test data will be as follows:
private IEnumerable<string> GetDirectoriesStub() { return new string[] { @"C:\Documents and Settings" ,@"C:\Program Files" ,@"C:\Program Files (x86)" ,@"C:\Users" ,@"C:\Windows" ,@"C:\git\gitlab.com" ,@"C:\Program Files\Common Files" ,@"C:\git\github.com" ,@"C:\Program Files\dotnet" ,@"C:\Program Files\Git" ,@"C:\Program Files\Git\bin" ,@"C:\Program Files\Git\dev\shm" ,@"C:\git" ,@"C:\Program Files\nodejs" ,@"C:\Program Files\Git\dev\mqueue" }; }
First of all, I count the number of \ characters in each line. The more such characters there are, the deeper the folder will lie, the more its level will be:
var paths = this.GetDirectoriesStub(); paths.Select(x => new { Path = x, Level = x.Count(y => y == '\\')} ) .Dump();
We get the following data set:

Now sort the way we want. Judging by the voiced conditions, it is necessary first to sort by the level of nesting, and secondly - by the folder name:
paths.Select(x => new { Path = x, Level = x.Count(y => y == '\\') }) .OrderBy(x => x.Level) .ThenBy(x => x.Path) .Dump();
It turns out like this:

Something ugly. Let's try changing the sorting: first by x.Path, then by x.Level:

It seems so much more logical and understandable.
Update
Very close, but not quite right. Note the "C: \ Program Files (x86)", which is located between the "C: \ Program Files" and "C: \ Program Files \ Common Files". And logically, it should be displayed after all nested in the "C: \ Program Files"
Here it is already possible to build a tree so that you can see which folders have which folders. But in principle, you can dodge and continue to do sorting.
Add some magic with weights:
paths.Select(x => new { Path = x, PathForSorting = (x + '\x01').Replace('\\', '\x02'), Level = x.Count(y => y == '\\') }) .OrderBy(x => x.PathForSorting) .ThenBy(x => x.Path) .ThenBy(x => x.Level) .Dump();

In principle, it works and if you remove .Replace('\\', '\x02') - but for reliability left the full version. (In the full version it will be possible to take into account some additional conditions if necessary)
paths.Select(x => new { Path = x, PathForSorting = (x + '\x01'),//.Replace('\\', '\x02'), Level = x.Count(y => y == '\\') }) .OrderBy(x => x.PathForSorting) .ThenBy(x => x.Path) .ThenBy(x => x.Level) .Dump();

The explanation of magic. Why was the first character entered? To be guaranteed to distinguish who is the parent and who is the descendant. If earlier it was enough to assume that "someone whose line length is shorter is the higher one in the sorting / hierarchy," then, taking into account the example, it is already necessary to determine more precisely.
I introduced the second symbol solely for clarity, choosing it more than the symbol1. Implicitly, the sorting rule "\ x01 show above \ x02" sounds like "the parent folder (this is the \ x01 symbol) is located above any subfolders in it (this is the symbol 2)". This rule is redundant and is introduced only for clarity, so that this rule can be verbalized (the explicit one is better than the implicit one).
In general, I believe that already in this place the amount of applied magic comes to the point where it is time to think about building a tree.
There are two reasons for this.
First, some non-obviousness of the algorithm (magic).
Secondly, it is quite possible that in your directory names there will be characters below the space (all kinds of curved folders) and in a real application it is better to avoid such hacks. Is it necessary for you, so that users of the program prefer other software that will not be buggy even in case of incorrect folders on the disk? )
aeverything inadisplayed? - Andrey NOPIEnumerable<Entry> Enumerate() { yield return this; foreach (var child in Children) foreach (var item in child.Enumerate()) yield return item; }IEnumerable<Entry> Enumerate() { yield return this; foreach (var child in Children) foreach (var item in child.Enumerate()) yield return item; }IEnumerable<Entry> Enumerate() { yield return this; foreach (var child in Children) foreach (var item in child.Enumerate()) yield return item; }- Andrey NOPIEnumerable<Entry> Enumerate() => Children.SelectMany(child => child.Enumerate()).Prepend(this);- Andrey NOP