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.