4

When attempting to read a file while calling DoSomething(); (from Something();) in the TestProgram_Load() method, I encounter a NullReferenceException, which I'm having trouble making sense of.

This happens when attempting to check if a file exists, or even attempting to read it. However, I am able to write to the file without an issue, and reference the string value, even in the debugger.

Here's the problem code:

// No matter the file name, this fails every time.
string fileName = "file.txt";

public void DoSomething()
{
    if (File.Exists(fileName)) // NullReferenceException
    {
        using (StreamReader r = new StreamReader(fileName)) // NullReferenceException
        {

        }
    }
}

And the method that calls it:

public void Something()
{
    // This works fine
    if (!File.Exists(fileName))
    {
        // This works fine
        using (StreamWriter w = new StreamWriter(fileName))
        {
             w.Write("Test");
        }
    }

   // Test to see if there's an issue with this method too...
   // This is fine, but whether or not File.Exists(fileName) is used, DoSomething(); has the same problem.

   if (File.Exists(fileName))
   { 
       DoSomething(); 
   }

}

Here's the TestProgram_Load method:

private void TestProgram_Load(object sender, EventArgs e)
{
    TestClass t = new TestClass();
    t.Something();
}

Here's the stack trace:

at TestProgram.TestClass.DoSomething() in Visual Studio 2015\Projects\Test Program\Test Program\Classes\FileSystem\TestClass.cs:line 39
at TestProgram.Program.Main() in Visual Studio 2015\Projects\Test Program\Test Program\Program.cs:line 19
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

And Line 39:

if (File.Exists(fileName))

This code is being executed in the main program's startup functions: either in the constructor, or the TestProgram_Load() method: both are having the same issue. There should not be any threading at all.

Here are some key details:

  1. I attempt to read the file, DoSomething();
  2. The string value exists in the debugger, and can be referenced right before File.Exists(fileName)
  3. File.Exists(fileName) works in a different method, but not this one.
  4. The string is not being updated at all.
  5. The string value is hard-coded.
  6. There are no additional threads to interfere with this.

I want this to actually detect existence and, of course, open the file. What's going on here?

leppie
  • 109,129
  • 16
  • 185
  • 292
Mark Buffalo
  • 719
  • 1
  • 9
  • 25
  • 2
    try starting visual studio in administrative mode. sounds like a permission issue – Muckeypuck Jul 20 '16 at 17:29
  • This sounds like very bizzarre behavior. Can we see a screenshot of your debugger window? – Sam I am says Reinstate Monica Jul 20 '16 at 17:29
  • @Muckeypuck Same issue as administrator. – Mark Buffalo Jul 20 '16 at 17:31
  • The posted code won't compile, and if you fix the typos, it works, so likely the issue is in the code you didn't post. Do you declare another fileName variable anywhere? If you right-click on the fileName that's not working nd select "Go To Definition", where does it go? – Anon Coward Jul 20 '16 at 17:33
  • One more thing to try then im stumped... move the file to a folder in your desktop and try it there – Muckeypuck Jul 20 '16 at 17:34
  • This sounds quite similar to this thread http://stackoverflow.com/questions/38470302/bug-triggering-if-and-else-at-the-same-time-unity-c-sharp#comment64344788_38470302. Strings seem to be coming up as null for some reason – keyboardP Jul 20 '16 at 17:34
  • Are you accidentally declaring the string in another method instead of in the class? – Matt Coats Jul 20 '16 at 17:35
  • 1
    @AnonCoward Fixed the typos, sorry. That was not the issue. I was renaming stuff to post here. Anyway, I've resolved that, but the problem is obviously still there. @MattCoats, no, it's not declared anywhere else. In fact, if I add `MessageBox.Show(fileName);` it works, then followed immediately by `if (File.Exists(fileName))`, it throws a `NullReferenceException`. – Mark Buffalo Jul 20 '16 at 17:37
  • @Muckeypuck Already tried that. Same deal. – Mark Buffalo Jul 20 '16 at 17:41
  • Sorry one more idea. Before you hit file.exists, get the filename and paste it into file explorer and see if it opens the file – Muckeypuck Jul 20 '16 at 17:45
  • @Muckeypuck I did that. The file does exist. It's created, written to, etc. If the file didn't exist, and I attempted to open it (at this point, I haven't opened it yet because of `NullReferenceException`), it would throw a `FileNotFoundException`, not a `NullReferenceException`. :P – Mark Buffalo Jul 20 '16 at 17:46
  • 5
    This has nothing to do with`fileName` being `null` as `File.Exists` will return `false` in that case and the `StreamReader` constructor would throw `ArgumentNullException`. Basically something is going horribly wrong in the .Net code. Can you include the entire stack trace? – juharr Jul 20 '16 at 17:50
  • @juharr I've updated this with the stack trace. – Mark Buffalo Jul 20 '16 at 18:09
  • 1
    If you use Debug.Write(fileName) straight after assigning it, does that also throw an exception. Additionally, if you go to the project properties...Debug...and enable the unmanaged code exception handling, does that provide any other details? – keyboardP Jul 20 '16 at 18:14
  • 3
    You show us line 19, but the stack trace says line 39 ?!? – Dirk Vollmar Jul 20 '16 at 18:17
  • What's at line 39 in TestClass.cs? – juharr Jul 20 '16 at 18:17
  • 1
    Possible duplicate of [What is a NullReferenceException, and how do I fix it?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – ManoDestra Jul 20 '16 at 18:17
  • @keyboardP `Debug.Write(fileName);` works fine right after assigning it. And it works inside of `DoSomething()` _until_ we check to see if it exists using `File.Exists()`. Enabling `Native Code Debugging` doesn't provide any other details. Also, fileName is still showing as "file.txt" – Mark Buffalo Jul 20 '16 at 18:19
  • 2
    @ManoDestra I wouldn't consider this a duplicate, it seems like a genuine bug not caused by OP's code (at this stage). I posted a comment earlier in this thread from yesterday facing a similar issue with String.IsNullOrEmpty returning true even though the string was assigned. – keyboardP Jul 20 '16 at 18:20
  • @DirkVollmar @juharr, Sorry, typed out the wrong line. It is indeed 39. *facepalms himself* @ThomasWeller, it's already been created, and then initialized through `InitializeComponent();`? – Mark Buffalo Jul 20 '16 at 18:21
  • Can you disable "Enable Just My Code" and provide the complete stack trace? – user1620220 Jul 20 '16 at 18:24
  • @user1620220 That's already disabled, and this is the complete stack trace. – Mark Buffalo Jul 20 '16 at 18:26
  • I assume you've tried to clean and rebuild? Does the vs hosting process remain in the list of processes when you close VS? What happens if you untick "Enable VS hosting process" in the project settings? – GSerg Jul 20 '16 at 18:29
  • @MarkBuffalo - What happens when you run it in release mode? I wonder if it's a debugger issue interfering with the runtime – keyboardP Jul 20 '16 at 18:35
  • @keyboardP Both Debug and Release give the same issue. :{ – Mark Buffalo Jul 20 '16 at 18:35
  • What environment is this executing in? I've followed the source code for File.Exists. When it gets down into Path.NormalizePath it branches off into a lot of environment-specific code. – Scott Hannen Jul 20 '16 at 18:36
  • 2
    @ThomasWeller `File.Exists` cannot raise `NullReferenceException`, yet it does for the OP. It would appear it's either a bug in the framework or a peculiar combination of unknown external conditions. In this situation being able to come up with a minimal, complete and verifiable example would itself be the answer to the OP's question. It is therefore not constructive to ask for one in these circumstances. – GSerg Jul 20 '16 at 18:37
  • 1
    @ScottHannen It's executing in a Windows environment, and in the directory where the executable is being ran. Note that `File.Exists()` _will_ work in `Something()`, but not `DoSomething()`. Code is exactly as it is. – Mark Buffalo Jul 20 '16 at 18:38
  • @MarkBuffalo - If you use a `String.IsNullOrEmpty` on `fileName`, does it return `true`? (even though it should be false) – keyboardP Jul 20 '16 at 18:38
  • 1
    @keyboardP There is no `String.IsNullOrEmpty` at all. And I can output `fileName` perfectly _until_ it gets to `File.Exists()`. @ThomasWeller I posted exactly where, and what my problem is, along with my desired outcome. I don't know what else to tell you, mate. – Mark Buffalo Jul 20 '16 at 18:39
  • @MarkBuffalo - I meant if you could add it and test :) Just seeing if these are related http://stackoverflow.com/questions/38470302/bug-triggering-if-and-else-at-the-same-time-unity-c-sharp#comment64344788_38470302 and http://stackoverflow.com/questions/17150131/string-isnullorempty-returns-true-when-supplied-string-is-not-null. Higher chance of it being a framework bug if they are – keyboardP Jul 20 '16 at 18:40
  • 1
    When something impossible happens, there's almost always an assumption being missed. We think we're seeing everything, but it's more likely that we're missing something than that something impossible is happening. You mentioned that there's no other threads. Just for the fun of it, can you put a `lock` around reads or writes to `fileName` or even just hard-code it in the functions instead of using a variable? – Scott Hannen Jul 20 '16 at 18:54
  • @ScottHannen Agreed. I also hard-coded it in the function. Same issue. – Mark Buffalo Jul 20 '16 at 19:04
  • Do you have a property or some variable named "File"? If so, for some reason File.Exists could be trying to access that property instead of the static method, and if that property were null at the time, trying to access an Exists method would cause the null reference error. This is just a shot in the dark though, I'm not sure why it would use the property instead of the static method. – Matt Coats Jul 20 '16 at 20:23
  • @MattCoats Nope, no such thing. I found the issue: an uninstantiated value that occurs long *after* `File.Exists()`, but the debugger was breaking on `File.Exists()`, and when opening the file, it wasn't giving any additional information. It appears my debugger is not working as anticipated. Now that I've solved the issue, I need to find out why my debugger is breaking long before the uninstantiated object is even called... – Mark Buffalo Jul 20 '16 at 20:30
  • As this is really getting weird, could you post the IL that is being generated (you get the IL using `ildasm.exe /all /out=consoleapp.il consoleapp.exe` on a Visual Studio command prompt)? – Dirk Vollmar Jul 20 '16 at 20:30
  • 2
    It sounds like your debugger was showing one version of the source code and executing another. I've had that happen. `File.Exists()` wasn't throwing the exception. Whatever was at that line in the executing code was throwing the exception. – Scott Hannen Jul 21 '16 at 01:01
  • 2
    [http://stackoverflow.com/questions/12416192/visual-studio-breakpoints-break-in-the-wrong-source-file-or-multiple-files-simu](http://stackoverflow.com/questions/12416192/visual-studio-breakpoints-break-in-the-wrong-source-file-or-multiple-files-simu), [http://stackoverflow.com/questions/6755825/visual-studio-code-out-of-sync-with-the-location-for-debug-source](http://stackoverflow.com/questions/6755825/visual-studio-code-out-of-sync-with-the-location-for-debug-source) – Scott Hannen Jul 21 '16 at 01:04
  • Things to try: 1. Restart your PC, 2. declare you filename as static, 3. Reinstall the .Net Framework/ Visual Studio. – kurakura88 Jul 21 '16 at 02:21

3 Answers3

2

What's interesting is that the documentation for File.Exists states:

The Exists method returns false if any error occurs while trying to determine if the specified file exists. This can occur in situations that raise exceptions such as passing a file name with invalid characters or too many characters, a failing or missing disk, or if the caller does not have permission to read the file.

My initial inclination was to believe that the write was still completing while you were trying to read, but according to the documentation, this should still just return false. It sounds like an internal .Net bug.

I don't have a clear cut answer, but you may be able to get to the root cause by:

  • Putting a Thread.Sleep after the write for 1000ms
  • Using a FileInfo instead of File (in case there's a bug in File
  • Don't check File.Exists and see if your stream gives you a more descriptive error

If those don't work, and you know the string works the first time, you can try switching to using the FileInfo class completely. Something like:

var file = new FileInfo(fileName);
if (!file.Exists())
{
    using (var writer = file.CreateText())
    {
        writer.Write("test");
    }
}
using (var writer = file.OpenText())
{
    // do stuff
}

Excuse my code if it doesn't build. I don't have visual studio installed on this device.

Michael Meadows
  • 26,178
  • 4
  • 45
  • 60
  • The write already completed, and was closed, unless somehow the `using` statement did not actually release the lock. However, that does not appear to be the case: I am immediately checking to see if the file exists afterwards inside of the `Something()` method. It only fails when I call `DoSomething()`, which is a unique method name. Not checking `File.Exists()` leads to the same issue, and same error. Everything referencing fileName seems to fail. – Mark Buffalo Jul 20 '16 at 18:33
  • To clarify, everything referencing `fileName` at the point where it does File.Exists(), inside of `DoSomething()`, or the `StreamReader`, is causing the same error and producing the same debug output. In `DoSomething()`, It will accept other uses of fileName before `File.Exists()` or `StreamReader` – Mark Buffalo Jul 20 '16 at 18:40
0

Never encountered this kind of bug before, but it appears to be a problem with my debugger and Stacktrace not giving the appropriate information. In a large code base, a List<String> object had yet not been instantiated in the beginning.

Normally, my debugger will tell me which object was not instantiated. Unfortunately, it kept complaining about the wrong item, a fileName string (bug?), and anything put inside of it. This was not running in a separate thread either.

After trial and error, it was discovered way down inside of the following line:

if (File.Exists(fileName)
{
      // [...] many lines down. Do lots of stuff.

      // Culprit
      Class.ListStringObject.Add("string");
}

Why it was breaking on this line, I have no clue, but I'd love to know if there's a way around that.

Mark Buffalo
  • 719
  • 1
  • 9
  • 25
-1

Make sure you have

using System.IO;

What is the runtime context? Is this IIS hosted or a windows execution environment?

In a web hosted environment you will want to do something like this:

var physicalFolder = HostingEnvironment.MapPath(VirtualFolder);
if (File.Exists(physicalFolder + fileName)){
    ...
}

In a windows runtime context you will want this:

var rootOfCurrentPath = Path.GetPathRoot(Environment.CurrentDirectory);
if (File.Exists(rootOfCurrentPath + fileName)){
    ...
}
Rod Hartzell
  • 420
  • 3
  • 9
  • 1
    Runtime context is the directory the file is being ran from. It's created with no problem, written to with no problem, but when checking if it exists in a different method, it has a problem. `System.IO` is obviously referenced because I wouldn't be able to write without it. – Mark Buffalo Jul 20 '16 at 17:39