1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu Resource Management pptx

5 306 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Resource management
Thể loại Presentation
Định dạng
Số trang 5
Dung lượng 23,51 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Disposal Methods An example of a class that implements a disposal method is the TextReader class from the System.IO namespace.. The StreamReader class which reads characters from a strea

Trang 1

Resource Management

Sometimes it's inadvisable to release a resource in a destructor; some resources are just too valuable and too scarce to lie around unreleased for arbitrary lengths of time Scarce resources need to be released, and they need to be released as soon as possible In these situations, your only option is to release the resource yourself A disposal method is a method that disposes of a resource If a class has a disposal method, you can call it

explicitly and thereby control when the resource is released

Disposal Methods

An example of a class that implements a disposal method is the TextReader class from the System.IO namespace This class provides mechanisms to read characters from a sequential stream of input TextReader contains a virtual method called Close, which closes the stream The StreamReader class (which reads characters from a stream, such as

an open file) and the StringReader class (which reads characters from a string) both derive from TextReader, and both override the Close method Here's an example that reads lines of text from a file by using the StreamReader class, and then displays them on the screen:

TextReader reader = new StreamReader(filename);

string line;

while ((line = reader.ReadLine()) != null)

{

Console.WriteLine(line);

}

reader.Close();

The ReadLine method reads the next line of text from the stream into a string The

ReadLine method returns null if there is nothing left in the stream It's important to call Close when you have finished with reader to release the file handle and associated

resources However, there is a problem with this example; it's not exception-safe If the call to ReadLine (or WriteLine) throws an exception, the call to Close will not happen; it will be bypassed If this happens often enough, you will run out of file handles and be unable to open any more files

Exception-Safe Disposal

One way to ensure that a disposal method (such as Close) is always called, regardless of whether there is an exception, is to call the disposal method inside a finally block Here's the previous example coded by using this technique:

Trang 2

TextReader reader = new StreamReader(filename);

try

{

string line;

while ((line = reader.ReadLine()) != null)

{

Console.WriteLine(line);

}

}

finally

{

reader.Close();

}

Using a finally block like this works, but it has several drawbacks that make it a less than ideal solution:

• It quickly gets unwieldy if you have to dispose of more than one resource (you end

up with nested try and finally blocks)

• In some cases, you might have to modify the code (for example, reorder the

declaration of the resource reference, remember to initialize the reference to null, and remember to check that the reference isn't null in the finally block)

• It fails to create an abstraction of the solution This means the solution is hard to

understand and you must repeat the code everywhere you need this functionality

• The reference to the resource remains in scope after the finally block This means

that you can accidentally try to use the resource after it has been released

The using statement is designed to solve all these problems

The using Statement

The using statement provides a clean mechanism for controlling the lifetimes of

resources You can create an object, and this object will be destroyed when the using statement block finishes

IMPORTANT

Do not confuse the using statement shown in this section with the using directive that brings a namespace into scope It is unfortunate that the same keyword has two different meanings

The syntax for a using statement is as follows:

using ( type variable = initialization ) embeddedStatement

Trang 3

Here is the best way to ensure that your code always calls Close on a TextReader: using (TextReader reader = new StreamReader(filename))

{

string line;

while ((line = reader.ReadLine()) != null)

{

Console.WriteLine(line);

}

}

This using statement is precisely equivalent to the following translation:

{

TextReader reader = new StreamReader(filename);

try

{

string line;

while ((line = reader.ReadLine()) != null)

{

Console.WriteLine(line);

}

}

finally

{

if (reader != null)

{

((IDisposable)reader).Dispose();

}

}

}

NOTE

Note the outer block scope This arrangement means that the variable you declare in a using statement goes out of scope at the end of the embedded statement

The variable you declare in a using statement must be of a type that implements the IDisposable interface The IDisposable interface lives in the System namespace and contains just one method called Dispose:

namespace System

{

interface IDisposable

{

Trang 4

void Dispose();

}

}

It just so happens that the StreamReader class implements the IDisposable interface, and its Dispose method calls Close to close the stream You can use a using statement as a clean, exception-safe, robust way to ensure that a resource is always automatically

released This solves all of the problems that existed in the manual try/finally solution You now have a solution that:

• Scales well if you need to dispose of multiple resources

• Doesn't distort the logic of the program code

• Abstracts away the problem and avoids repetition

• Is robust You can't use the variable declared inside the using statement, (in this case, reader) after the using statement has ended because it's not in scope

anymore—you'll get a compile-time error

Calling the Dispose Method from a Destructor

When writing a class, should you write a destructor, or implement the IDisposable

interface? A call to a destructor will happen but you just don't know when On the other hand you know exactly when a call to the Dispose method happens, but you just can't be sure that it will actually happen, because it relies on the programmer remembering to write a using statement However, it is possible to ensure that the Dispose method always runs by calling it from the destructor This acts as a useful backup You might forget to call the Dispose method, but at least you can be sure that it will be called, even if it's only when the program shuts down Here's an example of how to do this:

class Example : IDisposable

{

~Example()

{

Dispose();

}

public virtual void Dispose()

{

if (!this.disposed)

{

try {

// release scarce resource here

}

Trang 5

finally {

this.disposed = true;

GC.SuppressFinalize(this);

}

}

}

public void SomeBehavior() // example method

{

checkIfDisposed();

}

private void checkIfDisposed()

{

if (this.disposed)

{

throw new ObjectDisposedException("Example");

}

}

private Resource scarce;

private bool disposed = false;

}

Notice the following:

• The class implements IDisposable

• The destructor calls Dispose

• The Dispose method is public and can be called at any time

• The Dispose method can safely be called multiple times The variable disposed

indicates whether the method has aleady been run before The scarce resource is released only the first time the method runs

• The Dispose method calls the static GC.SuppressFinalize method This method

stops the garbage collector from calling the destructor on this object, because the object has now been finalized

• All the regular methods of the class (such as SomeBehavior) check to see whether

the object has already been disposed If it has, they throw an exception

Ngày đăng: 21/01/2014, 15:20

TỪ KHÓA LIÊN QUAN

w