tags:

views:

2198

answers:

6

In the Immediate Window

? System.IO.Path.Combine(@"C:\test",@"test")
"C:\\test\\test"
? System.IO.Path.Combine(@"C:\test",@"\test")
"\\test"

It seems that they should both be the same.

The old FileSystemObject.BuildPath() didn't work this way...

+2  A: 

Not knowing the actual details, my guess is that it makes an attempt to join like you might join relative URIs. For example:

join('/some/abs/path', '../other') = '/some/abs/other'

This means that when you join a path with a preceding slash, you are actually joining one base to another, in which case the second gets precedence.

elarson
+1  A: 

From MSDN:

If one of the specified paths is a zero-length string, this method returns the other path. If path2 contains an absolute path, this method returns path2.

In your example, path2 is absolute.

nickd
+14  A: 

This is kind of a philosophical question (which perhaps only Microsoft can truly answer), since it's doing exactly what the documentation says.

System.IO.Path.Combine

"If path2 contains an absolute path, this method returns path2."

I don't know what the rationale is. I guess the solution is to strip off (or Trim) DirectorySeparatorChar from the beginning of the second path; maybe write your own Combine method that does that and then calls Path.Combine().

Kyralessa
Looking at the disassembled code (check my post), you are right in a way.
Gulzar
I would guess it works that way to allow easy access to the "current working dir" algorithm.
BCS
+5  A: 

This is the disassembled code from Reflector for Path.Combine method. Check IsPathRooted function. If second path is rooted (starts with a DirectorySeparatorChar), return second path as it is.

public static string Combine(string path1, string path2)
{
    if ((path1 == null) || (path2 == null))
    {
        throw new ArgumentNullException((path1 == null) ? "path1" : "path2");
    }
    CheckInvalidPathChars(path1);
    CheckInvalidPathChars(path2);
    if (path2.Length == 0)
    {
        return path1;
    }
    if (path1.Length == 0)
    {
        return path2;
    }
    if (IsPathRooted(path2))
    {
        return path2;
    }
    char ch = path1[path1.Length - 1];
    if (((ch != DirectorySeparatorChar) && (ch != AltDirectorySeparatorChar)) && (ch != VolumeSeparatorChar))
    {
        return (path1 + DirectorySeparatorChar + path2);
    }
    return (path1 + path2);
}


public static bool IsPathRooted(string path)
{
    if (path != null)
    {
        CheckInvalidPathChars(path);
        int length = path.Length;
        if (((length >= 1) && ((path[0] == DirectorySeparatorChar) || (path[0] == AltDirectorySeparatorChar))) || ((length >= 2) && (path[1] == VolumeSeparatorChar)))
        {
            return true;
        }
    }
    return false;
}
Gulzar
+2  A: 

In my opinion this is a bug. The problem is that there are two different types of "absolute" paths. The path "d:\mydir\myfile.txt" is absolute, the path "\mydir\myfile.txt" is also considered to be "absolute" even though it is missing the drive letter. The correct behavior, in my opinion, would be to prepend the drive letter from the first path when the second path starts with the directory separator (and is not a UNC path). I would recommend writing your own helper wrapper function which has the behavior you desire if you need it.

Wedge
It matches the spec, but it's not what I would have expected either.
dthrasher
+2  A: 

I tried this code:

 String path1;
 String path2;
 String path3;

 path1 = "C:\\ProgramFiles\\";
 path2 = "..\\Users\\";
 path3 = System.IO.Path.Combine(path1, path2);
 MessageBox.Show(path3);

and got:

"C:\ProgramFiles\..\Users\"

It would be usefull if I could get

"C:\Users\"

Instead

Carlos Osuna
Use Path.GetFullPath() on the result.
Daniel Rose