CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Darrell Norton's Blog [MVP]

Fill in description here...

A Path.Combine method that takes any number of arguments

Python has a function similar to the .NET Framework’s Path.Combine method, except that Python can take any number of string parameters. I decided to port this to .NET. Here’s the code for a Utils.Path.Combine method that takes a string array of paths and returns the concatenated path:

     1: using System;
     2: using System.Text;
     3: using ioPath = System.IO.Path;
     4:  
     5: namespace Utils
     6: {
     7:     public sealed class Path
     8:     {
     9:         private Path() { }
    10:  
    11:         public static string Combine(params string[] paths) {
    12:             if (paths.Length == 2) return ioPath.Combine( paths[0], paths[1] );
    13:  
    14:             StringBuilder combined = new StringBuilder(50);
    15:             foreach(string path in paths) {
    16:                 if (path == null) throw new ArgumentNullException("path array item");
    17:                 Path.CheckInvalidPathChars(path);
    18:                 if ( path.Length > 0 ) {
    19:                     if (ioPath.IsPathRooted(path)) {
    20:                         combined = new StringBuilder(50).Append(path);
    21:                     }
    22:                     else {
    23:                         char ch1;
    24:                         if (combined.Length > 0) {
    25:                             ch1 = combined[combined.Length - 1];
    26:                         }
    27:                         else {
    28:                             ch1 = path[path.Length - 1];
    29:                         }
    30:                         if (((ch1 != ioPath.DirectorySeparatorChar) && 
    31:                                 (ch1 != ioPath.AltDirectorySeparatorChar)) && 
    32:                                 (ch1 != ioPath.VolumeSeparatorChar)) {
    33:                             combined.Append(ioPath.DirectorySeparatorChar);
    34:                             combined.Append(path);
    35:                         }
    36:                         else {
    37:                             combined.Append(path);
    38:                         }
    39:  
    40:                     }
    41:                 }
    42:             }
    43:             return combined.ToString();
    44:         }
    45:  
    46:         internal static void CheckInvalidPathChars(string path) {
    47:             if (-1 != path.IndexOfAny(System.IO.Path.InvalidPathChars)) {
    48:                 throw new ArgumentException("InvalidPathChars");
    49:             }
    50:         }
    51:     }
    52: }

You call it like this:

1: result = Path.Combine( @"C:\ProgramFiles", "someDir", @"anotherDir\", "someFile.txt" );

I tried to call the Path class's public members as much as possible to improve upgradability to the next version of the .NET Framework. The CheckInvalidPathChars internal method is the same as the System.IO.Path class's method of the same name. I used Reflector to check it out.

From my performance testing, the built-in Path.Combine performs about 60 nanoseconds faster on two arguments. For three arguments or more, it outperforms the built-in function in an increasing manner. Maybe it's not all that useful, but it was fun to do.

I did use Test-Driven Development, I just didn't show the code. The majority of the effort was in performance tuning, but the test harness kept the code running as intended.

Update: Changed lines 33-34 per James Curran's suggestion. I missed the boxing that line would cause. Now the code clearly outperforms the built-in Combine method for any number of paths greater than two.



Comments

Darrell said:

James - ok, you got me! I let that one boxing call in. I fixed the code. It now performs better than Path.Combine for any number of paths > 2 (before it was only marginally faster at 3, but now it's a lot faster).

Thanks!
# December 28, 2004 8:48 AM
Check out Devlicio.us!