views:

319

answers:

5

To combine two parts of a file path, you can do

System.IO.Path.Combine (path1, path2);

However, you can't do

System.IO.Path.Combine (path1, path2, path3);

Is there a simple way to do this?

Edit: I ended up using Aaron's helper method, but simplified it with Kha's advice:

public static string CombinePaths (params string [] paths)
{
    if (paths == null)
        throw new ArgumentNullException ("paths");

    return paths.Aggregate (Path.Combine);
}
+3  A: 

Nope - you have to call Path.Combine() several times.

You could write a helper method that does it for you, though:

public static string CombinePaths(params string[] paths) {
    if (paths == null) {
        return null;
    }
    string currentPath = paths[0];
    for (int i = 1; i < paths.Length; i++) {
        currentPath = Path.Combine(currentPath, paths[i]);
    }
    return currentPath;
}
Eilon
+1 - Perfect because you added no unnecessary LINQ.
ChaosPandion
Taking a look at the logic you can easily get rid of that second if statement.
ChaosPandion
@ChaosPandion: If you're going to avoid Linq then you should also optimize the Schlemiel-the-painter algorithm and instead use Path.PathSeparator and other static fields with a `StringBuilder`. I figured performance wasn't an issue here.
Aaronaught
Ah good point about the second if!
Eilon
"Unnecessary LINQ"? Perhaps you forgot to specify the [.net-2.0] tag?
Kyralessa
@ChaosPandion - "unnecessary Linq"? Maybe - if performance was critical. Or perhaps if only .Net 2. But actually the Linq approach is simple, concise and intentional. And if it gets people to think in functional terms it is no bad thing.
Rob Levine
I love LINQ as much as the next guy but come on for something as simple as this? You guys need to take it easy.
ChaosPandion
+3  A: 

Not simple, but clever :)

string str1 = "aaa", str2 = "bbb", str3 = "ccc";
string comb = new string[] { str1, str2, str3 }
    .Aggregate((x, y) => System.IO.Path.Combine(x, y));

Or:

string CombinePaths(params string[] paths)
{
    return paths.Aggregate((x,y) => System.IO.Path.Combine(x, y));
}
Aviad P.
+13  A: 

Here's a utility method you can use:

public static string CombinePaths(string path1, params string[] paths)
{
    if (path1 == null)
    {
        throw new ArgumentNullException("path1");
    }
    if (paths == null)
    {
        throw new ArgumentNullException("paths");
    }
    return paths.Aggregate(path1, (acc, p) => Path.Combine(acc, p));
}

Alternate code-golf version (shorter, but not quite as clear, semantics are a bit different from Path.Combine):

public static string CombinePaths(params string[] paths)
{
    if (paths == null)
    {
        throw new ArgumentNullException("paths");
    }
    return paths.Aggregate(Path.Combine);
}

Then you can call this as:

string path = CombinePaths(path1, path2, path3);
Aaronaught
@Downvoter: Let's hear it.
Aaronaught
This might be a stupid question, but where does Aggregate come from? I'm using Mono targeting Mono / .Net 3.5, and the compiler can't find it.
Matthew
`using System.Linq`.
SLaks
Ahh - `Aggregate` is an extension method in the `System.Linq` namespace, which is in `System.Core.dll`.
Aaronaught
Why the extra 'path1' parameter? Also, the last line can be shortened to `return paths.Aggregate(/*path1, */Path.Combine);`
Kha
@Kha: This is true, I wrote it that way to preserve the semantics of the original `Path.Combine` and to try to indicate clearly that at least one path is required for the method to work correctly. `Path.Combine` will throw an `ArgumentNullException` if either `path1` or `path2` are `null`. But you're absolutely right, it's not totally necessary.
Aaronaught
Kha: I like that simple version better. I edited my question to include the modified utility method.
Matthew
Resharper is so nice to suggest: "Use Method Group" (second return statement vesion)
George Polevoy
+7  A: 

As others have said, in .NET 3.5 and earlier versions there hasn't been a way to do this neatly - you either have to write your own Combine method or call Path.Combine multiple times.

But rejoice - for in .NET 4.0, there is this overload:

public static string Combine(
    params string[] paths
)

There are also overloads taking 3 or 4 strings, presumably so that it doesn't need to create an array unnecessarily for common cases.

Hopefully Mono will port those overloads soon - I'm sure they'd be easy to implement and much appreciated.

Jon Skeet
Shouldn't declaring single array be more efficient then declaring 4 different variables? What could be the reason for 4 or 3 string overload?
Hasan Khan
@Hasan: No, creating an array requires a separate object which has to be garbage collected later, etc. Passing two separate variables is more efficient than creating a new array containing two references.
Jon Skeet
Kha
http://msdn.microsoft.com/en-us/library/dd784047(VS.90).aspx states that Path.Combine will take 3 strings in .Net 3.5 which is clearly wrong since it gives a compiler error when used. the msdn library is wrong in this case. I put this here in case someone else lands on this page after getting this compiler error.
Maggie