3. finally?
The release solution relies on your current language. In C ++, you can use the Destructor built on the stack. In Java, You can construct finally blocks. C # allows you to create custom structure types, but does not allow destructor in the structure (only because a C # destructor is actually a Finally method, which is called by the garbage collector. Structure, which is a value type and does not belong to the recycle range of the garbage collector ). Therefore, at the beginning, C # must follow the Java path and use finally blocks. First, the finally block is enabled as follows:
Private static char [] ReadSource (string filename)
{
Try
{
FileInfo file = new FileInfo (filename );
Int length = (int) file. Length;
Char [] source = new char [length];
TextReader reader = file. OpenText ();
Reader. Read (source, 0, length );
}
Finally
{
Reader. Close ();
}
Return source;
}
This version has to introduce a try program block (since a finally program must be followed by a try program block soon), this will be a reasonable solution if it works. However, it does not. The problem is that the try block is built into a range, so the reader in the finally block is not in this range and the source in the returned statement is not in this range.
Finally?
To solve this problem, you have to move the declaration of reader and source outside the try block. The second attempt is as follows:
Private static char [] ReadSource (string filename)
{
TextReader reader;
Char [] source;
Try
{
FileInfo file = new FileInfo (filename );
Int length = (int) file. Length;
Source = new char [length];
Reader = file. OpenText ();
Reader. Read (source, 0, length );
}
Finally
{
Reader. Close ();
}
Return source;
}
This version moves the declaration of reader and source outside the try block, and then assigns them to reader and source but does not initialize them. This is another place different from the original "ideal" version (two additional lines appear ). However, you may think that if it works, it will be a reasonable solution. But it does not. The problem is that delegation is not equivalent to initialization and letting the compiler know about it. If an exception occurs before the reader is assigned, this is a call to reader. close () in the finally block.
According to the unallocated reader, C #, which is the same as Java, is not allowed.
Finally?
Obviously, you must initialize reader. The third attempt is as follows:
Private static char [] ReadSource (string filename)
{
TextReader reader = null;
Char [] source;
Try
{
FileInfo file = new FileInfo (filename );
Int length = (int) file. Length;
Source = new char [length];
Reader = file. OpenText ();
Reader. Read (source, 0, length );
}
Finally
{
Reader. Close ();
}
Return source;
}
This version introduces null values, which are not included in the original "ideal version. However, if you still think that it works, it will be a reasonable solution, but it is not (although it can be compiled ). The problem is that when you call reader. close (), it is easy to throw an NullReferenceException.
Finally?
One solution is to protect the eader. close () method. The fourth attempt is as follows:
Private static char [] ReadSource (string filename)
{
TextReader reader = null;
Char [] source;
Try
{
FileInfo file = new FileInfo (filename );
Int length = (int) file. Length;
Source = new char [length];
Reader = file. OpenText ();
Reader. Read (source, 0, length );
}
Finally
{
If (reader! = Null)
{
Reader. Close ();
}
}
Return source;
}
Of course, reader. close () protection is not an ideal version of ReadSource. However, if it is only effective, it will be a reasonable version. Ultimately, work. It is different from the original version. A little effort, you can reuse the following code:
Private static char [] ReadSource (string filename)
{
FileInfo file = new FileInfo (filename );
Int length = (int) file. Length;
Char [] source = new char [length];
TextReader reader = file. OpenText ();
Try
{
Reader. Read (source, 0, length );
}
Finally
{
If (reader! = Null)
{
Reader. Close ();
}
}
Return source;
}
In some cases, you can determine possible null values in the finally block (the above is an example), but in general, you 'd better judge it in the finally block (considering that if file. openText returns a null value, or if reader is put into the try block, or reader is passed to the try block as the ref/out parameter ). You have to add a try block, a finally block, and an if protection. If you are using Java, you have to do these things every time. This is the biggest problem. If this solution is annoying and totally different from the original "perfect" solution, it doesn't matter. You can extract these exceptions into one piece. In Java, you cannot do this. If an exception occurs, Java stops running and C # continues.
Iv. using statements
In C #, the using statement is the closest to the "ideal" version:
Private static char [] ReadSource (string filename)
{
FileInfo file = new FileInfo (filename );
Int length = (int) file. Length;
Char [] source = new char [length];
Using (TextReader reader = file. OpenText ())
{
Reader. Read (source, 0, length );
}
Return source;
}
Reader will be properly disabled. To put it simply, the using statement has a large number of features that can improve the "ideal" version at the beginning. First, let's take a look at its internal operating mechanism.
Using statement Conversion
C # ECMA standard description using statement:
Using (type variable = initialization)
EmbeddedStatement
It is equivalent
{
Type variable = initialization;
Try
{
EmbeddedStatement
}
Finally
{
If (