Home > Software design >  Scope issue in visual basic.net Unable to close stream object in finally clause ,getting System.Null
Scope issue in visual basic.net Unable to close stream object in finally clause ,getting System.Null

Time:06-08

I have the following Visual Basic.Net 16.x Program

Module Program

    Sub Main(args As String())

        Dim sFileName As String = "VBnet_TextFileIO.txt"
        Dim sTextToWrite As String = "Hello From VB.net"   vbCrLf   "Second Line "

        Dim myFileStreamWriter As StreamWriter = Nothing

        Try
            myFileStreamWriter = New StreamWriter(sFileName, 'Pass the file path and name to the StreamWriter constructor.
                                                 True)      'Indicate that Append is True, so file will not be overwritten.

            myFileStreamWriter.WriteLine(sTextToWrite)

            myFileStreamWriter.Close() 'control do not reach here when exception occurs

        Catch ex As Exception

            Console.WriteLine("An Exception Occurred")

        Finally

            myFileStreamWriter.Close() 'Compiler says System.NullReferenceException: 
                                       'Object reference not set to an instance of an 
                                        object.'


        End Try

    End Sub

End Module

Under the Finally Clause

Compiler complains that "System.NullReferenceException: 'Object reference not set to an instance of an object.' myFileStreamWriter was Nothing."

Why is the compiler complaining like it?,

I am assuming that myFileStreamWriter is out of scope under the Finally clause section. How should i rectify this?

How should i properly close the myFileStreamWriter object

The exception happening under try section is System.UnauthorizedAccessException created by making the file read only by me to create the error condition.

CodePudding user response:

No, the compiler doesn't tell you that at all. The compiler might give you a warning about a potential null reference but what you're reporting is a run-time exception.

The problem here is that the only line that can throw an exception in that Try block is the first one and, in that case, there will be no StreamWriter object created, in which case that variable will be Nothing. You can't close an object that was never created.

The code is poorly structured for a number of reasons. For one thing, you're calling Close in both the Try block and the Finally block. The whole point of a Finally block is to perform required cleanup, whether or not an exception is thrown. In your case, you would close the object twice if no exception was thrown. As there will be no object to close if an exception is thrown, you should call Close only in the Try block and do away with the Finally block.

It would be better still if you were to create the object with a Using statement, which guarantees disposal:

Try
    Using myFileStreamWriter = New StreamWriter(sFileName, 'Pass the file path and name to the StreamWriter constructor.
                                                True)      'Indicate that Append is True, so file will not be overwritten.
        myFileStreamWriter.WriteLine(sTextToWrite)
    End Using
Catch ex As Exception
    Console.WriteLine("An Exception Occurred")
End Try

It would be better still if you didn't create a StreamWriter yourself at all:

Try
    File.AppendAllText(sFileName, sTextToWrite)
Catch ex As Exception
    Console.WriteLine("An Exception Occurred")
End Try

Finally, you should pretty much never catch the Exception type. Only catch exceptions that you reasonably believe could be thrown, in which case you will no exactly what specific type they will be. You should also log the exception somewhere. You should then handle the UnhandledException event of the application to catch and log any unanticipated exceptions and shut down gracefully instead of crashing.

  • Related