2

I'm working on a series of methods that will test a given path to determine if it is (or, at least could be) valid. I have a couple of overloads that will accept either an IO.FileInfo object or an IO.DirectoryInfo object - which I'd personally prefer to use to help in catching invalid characters as soon as possible in the process. One piece of information I "need" to get as a part of the process is basically the original value the user presented - especially in the case of an IO.FileInfo or IO.DirectoryInfo object as those will automatically prepend the Environment.CurrentDirectory value to any string it determines to be a relative path.

For example:

Dim TestFile As New IO.FileInfo("Testing\This is a test")

Instantiates an IO.FileInfo object with the following properties (among others):

  • DirectoryName - "C:\Development\My Solution\My Project\bin\Debug\Testing"
  • Exists - False
  • Extension - ""
  • FullName - "C:\Development\My Solution\My Project\bin\Debug\Testing\This is a test"
  • Name - "This is a test"
  • OriginalPath - "Testing\This is a test"

This last property is the one I'm most interested in. It's a Protected property of the IO.FileInfo class, which is inherited from the IO.FileSystemInfo class, but it seems to be the best possible way to retrieve the original value passed to the IO.FileInfo constructor. Obviously, I can't access the property directly with a simple Dim TestPath As String = TestFile.OriginalPath - the IDE gives shows the error "'System.IO.FileSystemInfo.OriginalPath' is not accessible in this context because it is 'Protected'" - so I can only think of one way to get this specific piece of information: Create a whole new class that inherits IO.FileSystemInfo with a Public property for the OriginalPath that reads from the base class.

PLEASE NOTE: I do have an overloading method that accepts a String value, but I was actually thinking of trying to "hide" that one behind a Private modifier so that only FileInfo and DirectoryInfo objects could be used to call this method. My primary reasoning there is that, if a FileInfo or DirectoryInfo object fails to instantiate due to invalid characters in the string (or any other reason), there's no reason for me to make the call to this method and I may be able to "clean up" the code a little.

Regardless, the creation of a whole separate class that's really only going to be used to access this one property in this one specific scenario seems like an awful lot of overhead for what should (or, at least could) be a fairly simple thing. Unfortunately, I can't think of any other way to extract that information and I'm just wondering if I may be over-thinking this.

In the meantime, I've gone ahead and created a TempFileInfo class for testing (NOTE: I haven't actually tested it yet) without explicitly implementing any "custom" code for any of the regular Public properties (required when inheriting from the IO.FileSystemInfo class):

Private Class TempFileInfo
    Inherits IO.FileSystemInfo

    Public Overrides ReadOnly Property Name As String
        Get
            Throw New NotImplementedException()
        End Get
    End Property

    Public Overrides ReadOnly Property Exists As Boolean
        Get
            Throw New NotImplementedException()
        End Get
    End Property

    Public Overrides Sub Delete()
        Throw New NotImplementedException()
    End Sub

    Public Shadows ReadOnly Property OriginalPath As String
        Get
            Return MyBase.OriginalPath
        End Get
    End Property

    Public Shared Widening Operator CType(v As FileInfo) As TempFileInfo
        Dim FSI As FileSystemInfo = v

        Return CType(FSI, TempFileInfo)
    End Operator
End Class

You'll note that I also included a Widening Operator that should allow me to convert from a "regular" IO.FileInfo object to my TempFileInfo object so that I can access my "custom" OriginalPath property. This is the only way I've found so far to "get there from here", but I wanted to go ahead and ask here in case there are other suggestions or things I might be overlooking.

The only "saving grace" for this method of implementation is that, because the "custom" TempFileInfo, the standard IO.FileInfo, and the standard IO.DirectoryInfo classes all inherit from the IO.FileSystemInfo class, I should be able to simply create an overloaded Widening Operator method for converting both IO.FileInfo objects as well as IO.DirectoryInfo objects instead of having to create a separate TempDirInfo class.

G_Hosa_Phat
  • 976
  • 2
  • 18
  • 38
  • 1
    Perhaps instead of extending `FileInfo`, you could just *contain* it in a wrapper class that saves the original path passed to its constructor, creates a `FileInfo` from it and passes the rest of its properties? That'd be just about as much work, but it smells a tiny bit better. – Ross Presser Oct 16 '19 at 15:23
  • 1
    Your approach appears to be pretty clean. The other method would be to use reflection to read the property directly.. but that violates the intent of the FileInfo and DirectoryInfo authors. It's kind of like performing open heart surgery to help someone pass gas. – Sam Axe Oct 16 '19 at 15:24
  • 4
    You probaly missed the `[FileInfo].ToString()` override. It returns the internal `DisplayPath` property value, which is the same as the `OriginalPath` field of the base class. – Jimi Oct 16 '19 at 17:18
  • @RossPresser - Thanks for the suggestion. I may have to consider that as I'm having some difficulty with the "final" implementation I proposed above. – G_Hosa_Phat Oct 16 '19 at 17:22
  • @SamAxe - Thank you. The fact that I'm really only needing the value for this one, specific, rather edge-case scenario leads me to think that reflection may not be the *worst* way to go about it, but it *is* a bit of overkill... – G_Hosa_Phat Oct 16 '19 at 17:24
  • 2
    @Jimi - Okay, *SERIOUSLY*?!? I mean, I knew that the `ToString()` method is available, but never even thought about using it for this purpose. I don't think I've (personally) ever called `ToString()` on a `FileInfo` object b/c I usually use one of the properties for anything to do with the path string (`.Name`, `.FullName`, `.DirectoryName`, etc.) I'm going to do a bit of testing, but if it's that simple, I'm going to be pretty upset with myself... ***Initial tests seem to indicate that this is DEFINITELY the way to go. Thank you so much!*** – G_Hosa_Phat Oct 16 '19 at 17:31
  • @Jimi - Just FYI, the tooltip for the `ToString()` method (which I *just* looked at) of the `FileInfo` class says: "*`Returns the path as a string.`*" However, the tooltip for the `ToString()` method of the `DirectoryInfo` class is a bit more informative: "*`Returns the original path that was passed by the user.`*" It'd be nice if the documentation were a bit more consistent there, but I'm certainly not one to cast stones. Please post your comment as an answer so I can accept it. – G_Hosa_Phat Oct 16 '19 at 17:46

1 Answers1

4

The path entered when a FileInfo or DirectoryInfo object is created is stored in the protected String OriginalPath field - which is used for serialization purposes - and the internal DisplayPath property, which is used as an internal reference.

When the class object is initialized (see the Init() method in the .Net source code), the path entered is stored in both the OriginalPath Field and the DisplayPath Property.

Both classes don't provide a public property to retrieve the initial path used to create the object.
They both, instead, return the DisplayPath property value as an override to the ToString() method:

Dim fInfo = New FileInfo("\SomePath\SomeFileName.ext")
Dim originalPath = fInfo.ToString()

var fInfo = new FileInfo(@"\SomePath\SomeFileName.ext");
string originalPath = fInfo.ToString();
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • 2
    So, in other words, I *was* over-thinking it. The tooltip for the `DirectoryInfo` object's `ToString()` method is a bit more descriptive and helpful in explaining this reality than that for a `FileInfo` object, but this helps tremendously. Thank you for the detailed explanation with the .NET source code reference. Extremely helpful, all around. – G_Hosa_Phat Oct 16 '19 at 18:31