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

Lập trình ứng dụng nâng cao (phần 6) potx

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

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Lập trình ứng dụng nâng cao (phần 6)
Trường học University of Information Technology, Vietnam National University Ho Chi Minh City
Chuyên ngành Programming
Thể loại Lecture notes
Thành phố Ho Chi Minh City
Định dạng
Số trang 50
Dung lượng 204,24 KB

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

Nội dung

However, keep inmind that in a real search, you would probably use only a part of the source stringrather than the entire source string, as shown here: // group time = one or more digits

Trang 1

Example 10-6 is identical to Example 10-5, except that the latter example doesn’tinstantiate an object of typeRegex Instead, Example 10-6 uses the staticversion ofSplit( ), which takes two arguments: a string to search for, and a regular expressionstring that represents the pattern to match.

The instance method ofSplit( )is also overloaded with versions that limit the ber of times the split will occur as well as determine the position within the targetstring where the search will begin

num-Using Regex Match Collections

Two additional classes in the NET RegularExpressions namespace allow you tosearch a string repeatedly, and to return the results in a collection The collectionreturned is of type MatchCollection, which consists of zero or more Match objects.Two important properties of aMatchobject are its length and its value, each of whichcan be read as illustrated in Example 10-7

string s1 = "One,Two,Three Liberty Associates, Inc.";

StringBuilder sBuilder = new StringBuilder( );

string string1 = "This is a test string";

Example 10-6 Using static Regex.Split( ) (continued)

Trang 2

Example 10-7 creates a simple string to search:

string string1 = "This is a test string";

and a trivial regular expression to search it:

Regex theReg = new Regex(@"(\S+)\s");

The string \S finds nonwhitespace, and the plus sign indicates one or more Thestring\s(note lowercase) indicates whitespace Thus, together, this string looks forany nonwhitespace characters followed by whitespace

Remember that the at (@) symbol before the string creates a verbatim

string, which avoids having to escape the backslash (\) character.

The output shows that the first four words were found The final word wasn’t foundbecause it isn’t followed by a space If you insert a space after the wordstring, andbefore the closing quotation marks, this program finds that word as well

// find any nonwhitespace followed by whitespace

Regex theReg = new Regex(@"(\S+)\s");

// get the collection of matches

MatchCollection theMatches = theReg.Matches(string1);

// iterate through the collection

foreach (Match theMatch in theMatches)

Trang 3

Thelength property is the length of the captured substring, and I discuss it in thesection “Using CaptureCollection” later in this chapter.

Using Regex Groups

It is often convenient to group subexpression matches together so that you can parseout pieces of the matching string For example, you might want to match on IPaddresses and group all IP addresses found anywhere within the string

IP addresses are used to locate computers on a network, and typically

have the form x.x.x.x, where x is generally any digit between 0 and

string string1 = "04:03:27 127.0.0.0 LibertyAssociates.com";

// group time = one or more digits or colons followed by space

Regex theReg = new Regex(@"(?<time>(\d|\:)+)\s" +

// ip address = one or more digits or dots followed by space

@"(?<ip>(\d|\.)+)\s" +

// site = one or more characters

@"(?<site>\S+)");

Trang 4

Again, Example 10-8 begins by creating a string to search:

string string1 = "04:03:27 127.0.0.0 LibertyAssociates.com";

This string might be one of many recorded in a web server logfile or produced as theresult of a search of the database In this simple example, there are three columns:one for the time of the log entry, one for an IP address, and one for the site, each sep-arated by spaces Of course, in an example solving a real-life problem, you mightneed to do more complex queries and choose to use other delimiters and more com-plex searches

In Example 10-8, we want to create a singleRegexobject to search strings of this typeand break them into three groups: time, ip address, andsite The regular expres-sion string is fairly simple, so the example is easy to understand However, keep inmind that in a real search, you would probably use only a part of the source stringrather than the entire source string, as shown here:

// group time = one or more digits or colons

// followed by space

Regex theReg = new Regex(@"(?<time>(\d|\:)+)\s" +

// ip address = one or more digits or dots

// get the collection of matches

MatchCollection theMatches = theReg.Matches(string1);

// iterate through the collection

foreach (Match theMatch in theMatches)

Trang 5

The parentheses create a group Everything between the opening parenthesis (justbefore the question mark) and the closing parenthesis (in this case, after the+sign) is

a single unnamed group

The string ?<time> names that group time, and the group is associated with thematching text, which is the regular expression (\d|\:)+)\s This regular expressioncan be interpreted as “one or more digits or colons followed by a space.”

Similarly, the string?<ip>names theipgroup, and?<site>names thesitegroup AsExample 10-7 does, Example 10-8 asks for a collection of all the matches:

MatchCollection theMatches = theReg.Matches(string1);

Example 10-8 iterates through theMatches collection, finding eachMatch object

If the Length of theMatch is greater than0, a Match was found; it prints the entirematch:

In Example 10-8, theMatches collection has only oneMatch It is possible, however,

to match more than one expression within a string To see this, modifystring1 inExample 10-8 to provide severallogFile entries instead of one, as follows:

string string1 = "04:03:27 127.0.0.0 LibertyAssociates.com " +

"04:03:28 127.0.0.0 foo.com " +

"04:03:29 127.0.0.0 bar.com " ;

This creates three matches in the MatchCollection, called theMatches Here’s theresulting output:

Trang 6

For eachMatch item found, you can print the entire match, various groups, or both.

Using CaptureCollection

Please note that we are now venturing into advanced use of regular expressions,which themselves are considered a black art by many programmers Feel free to skipover this section if it gives you a headache, and come back to it if you need it

Each time aRegexobject matches a subexpression, aCaptureinstance is created andadded to a CaptureCollection collection Each Capture object represents a singlecapture

Each group has its own capture collection of the matches for the subexpression ciated with the group

asso-So, taking that apart, if you don’t createGroups, and you match only once, you end

up with oneCaptureCollectionwith oneCaptureobject If you match five times, youend up with oneCaptureCollection with fiveCapture objects in it

If you don’t create groups, but you match on three subexpressions, you will end upwith three CaptureCollections, each of which will have Capture objects for eachmatch for that subexpression

Finally, if you do create groups (e.g., one group for IP addresses, one group formachine names, one group for dates), and each group has a few capture expressions,you’ll end up with a hierarchy: each group collection will have a number of capturecollections (one per subexpression to match), and each group’s capture collectionwill have a capture object for each match found

A key property of theCaptureobject is itslength, which is the length of the capturedsubstring When you askMatch for its length, it isCapture.Length that you retrievebecauseMatch derives fromGroup, which in turn derives fromCapture

Trang 7

The regular expression inheritance scheme in NET allows Match to

include in its interface the methods and properties of these parent

classes In a sense, a Group is-a capture: it is a capture that

encapsu-lates the idea of grouping subexpressions A Match, in turn, is-a Group:

it is the encapsulation of all the groups of subexpressions making up

the entire match for this regular expression (See Chapter 5 for more

about the is-a relationship and other relationships.)

Typically, you will find only a singleCapturein aCaptureCollection, but that neednot be so Consider what would happen if you were parsing a string in which thecompany name might occur in either of two positions To group these together in asingle match, create the?<company>group in two places in your regular expressionpattern:

Regex theReg = new Regex(@"(?<time>(\d|\:)+)\s" +

string string1 = "04:03:27 Jesse 0.0.0.127 Liberty ";

The string includes names in both of the positions specified Here is the result:theMatch: 04:03:27 Jesse 0.0.0.127 Liberty

Example 10-9 Examining the Captures collection

// the string to parse

// note that names appear in both

Trang 8

// searchable positions

string string1 =

"04:03:27 Jesse 0.0.0.127 Liberty ";

// regular expression that groups company twice

Regex theReg = new Regex(@"(?<time>(\d|\:)+)\s" +

// iterate through the collection

foreach (Match theMatch in theMatches)

// iterate over the captures collection

// in the company group within the

// groups collection in the match

foreach (Capture cap in

Trang 9

The code in bold iterates through theCaptures collection for theCompany group:foreach (Capture cap in

theMatch.Groups["company"].Captures)

Let’s review how this line is parsed The compiler begins by finding the collectionthat it will iterate over.theMatchis an object that has a collection namedGroups TheGroupscollection has an indexer that takes a string and returns a singleGroupobject.Thus, the following line returns a singleGroup object:

theMatch.Groups["company"]

TheGroupobject has a collection namedCaptures Thus, the following line returns aCaptures collection for the Group stored at Groups["company"] within the theMatchobject:

theMatch.Groups["company"].Captures

The foreach loop iterates over the Captures collection, extracting each element inturn and assigning it to the local variablecap, which is of typeCapture You can seefrom the output that there are two capture elements:JesseandLiberty The secondone overwrites the first in the group, and so the displayed value is justLiberty How-ever, by examining the Captures collection, you can find both values that werecaptured

Trang 10

Chapter 11 CHAPTER 11

Exceptions11

Like many object-oriented languages, C# handles abnormal conditions with

excep-tions An exception is an object that encapsulates information about an unusual

program occurrence

It is important to distinguish between bugs, errors, and exceptions A bug is a

pro-grammer mistake that should be fixed before the code is shipped Exceptions aren’t aprotection against bugs Although a bug might cause an exception to be thrown, youshould not rely on exceptions to handle your bugs Rather, you should fix the bugs

An error is caused by user action For example, the user might enter a number where

a letter is expected Once again, an error might cause an exception, but you can vent that by catching errors with validation code Whenever possible, errors should

pre-be anticipated and prevented

Even if you remove all bugs and anticipate all user errors, you will still run into able but unpreventable problems, such as running out of memory or attempting toopen a file that no longer exists You can’t prevent exceptions, but you can handlethem so that they don’t bring down your program

predict-When your program encounters an exceptional circumstance, such as running out of

memory, it throws (or “raises”) an exception When an exception is thrown,

execu-tion of the current funcexecu-tion halts, and the stack is unwound until an appropriateexception handler is found (see the sidebar, “Unwinding the Stack”)

This means that if the currently running function doesn’t handle the exception, thecurrent function will terminate, and the calling function will get a chance to handlethe exception If none of the calling functions handles it, the exception willultimately be handled by the CLR, which will abruptly terminate your program

An exception handler is a block of code designed to handle the exception you’ve

thrown Exception handlers are implemented ascatchstatements Ideally, if the tion is caught and handled, the program can fix the problem and continue Even ifyour program can’t continue, by catching the exception, you have an opportunity toprint a meaningful error message and terminate gracefully

Trang 11

excep-If there is code in your function that must run regardless of whether an exception isencountered (e.g., to release resources you’ve allocated), you can place that code in afinally block, where it is certain to run, even in the presence of exceptions.

Throwing and Catching Exceptions

In C#, you can throw only objects of typeSystem.Exception, or objects derived fromthat type The CLR System namespace includes a number of exception types thatyour program can use These exception types include ArgumentNullException,InvalidCastException, andOverflowException, as well as many others

C++ programmers take note: in C#, not just any object can be

thrown—it must be derived from System.Exception.

The throw Statement

To signal an abnormal condition in a C# class, you throw an exception To do this,use the keywordthrow This line of code creates a new instance ofSystem.Exceptionand then throws it:

throw new System.Exception( );

Throwing an exception immediately halts execution of the current “thread” (seeChapter 21 for a discussion of threads) while the CLR searches for an exception han-dler If an exception handler can’t be found in the current method, the runtime

Unwinding the Stack

When a method is called, an area is set aside on the stack, known as the stack frame,

which holds the return address of the next instruction in the calling method, the ments passed into the called method, and all the local variables in the called method.BecauseMethodAcan callMethodBwhich can callMethodCwhich can, in fact, callMethodA

argu-(which can even callMethodA!), and so on, “unwinding the stack” refers to the process

of finding the return address of the calling method and returning to that methodperemptorily, looking for acatchblock to handle the exception The stack may have

to “unwind” through a number of called methods before it finds a handler Ultimately,

if it unwinds all the way tomainand no handler is found, a default handler is called,and the program exits

Assuming a handler is found, the program continues from the handler, not from where

the exception was thrown, or from the method that called the method in which theexception was thrown (unless that method had the handler) Once unwound, the stackframe is lost

Trang 12

unwinds the stack, popping up through the calling methods until a handler is found.

If the runtime returns all the way throughMain( )without finding a handler, it nates the program Example 11-1 illustrates

termi-When you run this program in debug mode, an “Exception was unhandled” sage box comes up, as shown in Figure 11-1

mes-If you click View Detail, you find the details of the unhandled exception, as shown inFigure 11-2

This simple example writes to the console as it enters and exits each method.Main( )creates an instance of typeTestand callFunc1( ) After printing out theEnter Func1message,Func1( )immediately callsFunc2( ).Func2( )prints out the first message andthrows an object of typeSystem.Exception

Example 11-1 Throwing an exception

Trang 13

Execution immediately shifts to handling the exceptions The CLR looks to seewhether there is a handler inFunc2( ) There is not, and so the runtime unwinds thestack (never printing theexitstatement) toFunc1( ) Again, there is no handler, andthe runtime unwinds the stack back toMain( ) With no exception handler there, thedefault handler is called, which opens the exception message box.

The catch Statement

In C#, an exception handler is called a catch block and is created with the catchkeyword

In Example 11-2, the throw statement is executed within a tryblock, and a catchblock is used to announce that the error has been handled

Figure 11-1 Unhandled exception

Figure 11-2 Exception details

Trang 14

Example 11-2 Catching an exception

Console.WriteLine("Entering try block ");

throw new System.ApplicationException( );

Console.WriteLine("Exiting try block ");

}

catch

{

// simplified for this book; typically you would

// correct (or at least log) the problem

Console.WriteLine("Exception caught and handled.");

Entering try block

Exception caught and handled.

Trang 15

Example 11-2 is identical to Example 11-1 except that now the program includes atry/catch block.

It is a common mistake to clutter your code withtry/catch blocks that don’t ally do anything and don’t solve the problem that the exception is pointing out It isgood programming practice to use atry/catchblock only where yourcatch has theopportunity to rectify the situation (with the exception of the topmost level where, at

actu-a minimum, you wactu-ant to factu-ail reactu-asonactu-ably gractu-acefully)

An exception to this practice is to catch and log the exception, and then rethrow itfor it to be handled at a higher level, or to catch the exception, add context informa-tion, and then nest that information bundled inside a new exception, as describedlater in this chapter

Catch statements can be generic, as shown in the previous example, or can be geted at specific exceptions, as shown later in this chapter

tar-Taking corrective action

One of the most important purposes of acatchstatement is to take corrective action.For example, if the user is trying to open a read-only file, you might invoke a methodthat allows the user to change the attributes of the file If the program has run out ofmemory, you might give the user an opportunity to close other applications If allelse fails, thecatchblock can log the error (or even send out email) so that you knowspecifically where in your program you are having the problem

Unwinding the call stack

Examine the output of Example 11-2 carefully You see the code enter Main( ),Func1( ), Func2( ), and thetryblock You never see it exit the tryblock, though itdoes exitFunc2( ),Func1( ), andMain( ) What happened?

When the exception is thrown, the normal code path is halted immediately and trol is handed to thecatchblock It never returns to the original code path It never

con-gets to the line that prints theexitstatement for thetryblock Thecatchblock dles the error, and then execution falls through to the code followingcatch

han-Withoutcatch, the call stack unwinds, but withcatch, it doesn’t unwind, as a result

of the exception The exception is now handled; there are no more problems, andthe program continues This becomes a bit clearer if you move thetry/catchblocks

up toFunc1( ), as shown in Example 11-3

Trang 16

Example 11-3 Catch in a calling function

Trang 17

This time the exception is not handled in Func2( ), it is handled in Func1( ) WhenFunc2( )is called, it prints theEnterstatement, and then throws an exception Execu-tion halts and the runtime looks for a handler, but there isn’t one The stackunwinds, and the runtime finds a handler inFunc1( ) Thecatchstatement is called,and execution resumes immediately following thecatchstatement, printing theExitstatement forFunc1( ) and then forMain( ).

Make sure you are comfortable with why the Exiting Try Block statement and theExit Func2statement aren’t printed This is a classic case where putting the code into

a debugger and then stepping through it can make things very clear

Try/Catch Best Practices

So far, you’ve been working only with genericcatchstatements Best practices, ever, dictate that you want, whenever possible, to create dedicatedcatchstatementsthat will handle only some exceptions and not others, based on the type of excep-tion thrown Example 11-4 illustrates how to specify which exception you’d like tohandle

how-Example 11-4 Specifying the exception to catch

// try to divide two numbers

// handle possible exceptions

public void TestFunc( )

Trang 18

In this example, theDoDivide( )method doesn’t let you divide 0 by another number,nor does it let you divide a number by 0 It throws an instance ofDivideByZeroException if you try to divide by 0 If you try to divide 0 by anothernumber, there is no appropriate exception; dividing 0 by another number is a legalmathematical operation, and shouldn’t throw an exception at all For the sake of thisexample, assume you don’t want 0 to be divided by any number and throw anArithmeticException.

When the exception is thrown, the runtime examines each exception handler in

order and matches the first one it can When you run this witha=5andb=7, the put is:

out-5 / 7 = 0.71428out-571428out-57143

As you’d expect, no exception is thrown However, when you change the value ofa

to0, the output is:

} // end Test function

// do the division if legal

public double DoDivide(double a, double b)

{

if (b == 0)

throw new System.DivideByZeroException( );

if (a == 0)

throw new System.ArithmeticException( );

// throw new ApplicationException( );

Trang 19

The exception is thrown, and the runtime examines the first exception,DivideByZeroException Because this doesn’t match, it goes on to the next handler,ArithmeticException, which does match.

In a final pass through, suppose you change a to 7 and b to 0 This throws theDivideByZeroException

You have to be particularly careful with the order of the catch

state-ments because the DivideByZeroException is derived from

ArithmeticException If you reverse the catch statements, the

DivideByZeroException matches the ArithmeticException handler, and

the exception won’t get to the DivideByZeroException handler In fact,

if their order is reversed, it’s impossible for any exception to reach the

DivideByZeroException handler The compiler recognizes that the

DivideByZeroException handler can’t be reached and reports a

com-pile error!

When catching the generic exception, it is often a good idea to at least log as muchabout the exception as possible by callingToStringon the exception To see this atwork, make three changes to the previous example:

• Change the declared value ofb from0 to2

• Uncomment the penultimate line of code

• Comment out the final line of code (as it will now be unreachable)

The output will look something like this:

Log this: System.SystemException: System error.

at SpecifyingCaughtException.Test.DoDivide(Double a, Double b) in C:\ \Specified

Exception

s\Program.cs:line 53

Notice that among other things, the generic exception tells you the file, the method,and the line number; this can save quite a bit of debugging time

The finally Statement

In some instances, throwing an exception and unwinding the stack can create aproblem For example, if you have opened a file or otherwise committed a resource,you might need an opportunity to close the file or flush the buffer

If there is some action you must take regardless of whether an exception is thrown(such as closing a file), you have two strategies to choose from One approach is toenclose the dangerous action in atryblock, and then to close the file in both thecatch and tryblocks However, this is an ugly duplication of code, and it’s error-prone C# provides a better alternative in thefinally block

Trang 20

The code in thefinallyblock is guaranteed to be executed regardless of whether anexception is thrown TheTestFunc( )method in Example 11-5 simulates opening afile as its first action The method undertakes some mathematical operations, and thefile is closed It is possible that some time between opening and closing the file anexception will be thrown.

Keep the code in your finally block simple If an exception is thrown

from within your finally block, your finally block will not complete.

If this were to occur, it would be possible for the file to remain open The developerknows that no matter what happens, at the end of this method the file should beclosed, so the file close function call is moved to a finallyblock, where it will beexecuted regardless of whether an exception is thrown

Example 11-5 Using a finally block

// try to divide two numbers

// handle possible exceptions

public void TestFunc( )

Trang 21

In this example, one of thecatch blocks is eliminated to save space, and afinallyblock is added Whether or not an exception is thrown, the finally block is exe-cuted (in both output examples you see the messageClose file here.).

You can create a finally block with or without catch blocks, but a

finally block requires a try block to execute It is an error to exit a

finally block with break, continue, return, or goto.

Exception Objects

So far, you’ve been using the exception as a sentinel—that is, the presence of theexception signals the error—but you haven’t touched or examined the Exceptionobject itself TheSystem.Exceptionobject provides a number of useful methods andproperties TheMessageproperty provides information about the exception, such as

// do the division if legal

public double DoDivide(double a, double b)

This line may or may not print

Close file here.

Example 11-5 Using a finally block (continued)

Trang 22

why it was thrown TheMessageproperty is read-only; the code throwing the tion can set theMessage property as an argument to the exception constructor.TheHelpLinkproperty provides a link to the help file associated with the exception.This property is read/write.

excep-VB 6 programmers take note: in C#, you need to be careful when

declaring and instantiating object variables on the same line of code If

there is a possibility that an error could be thrown in the constructor

method, you might be tempted to put the variable declaration and

instantiation inside the try block But, if you do that, the variable will

only be scoped within the try block, and it can’t be referenced within

the catch or finallyblocks The best approach is to declare the object

variable before thetry block and instantiate it within the try block.

TheStackTraceproperty is read-only and is set by the runtime In Example 11-6, theException.HelpLinkproperty is set and retrieved to provide information to the userabout theDivideByZeroException TheStackTraceproperty of the exception can pro-

vide a stack trace for the error statement A stack trace displays the call stack: the

series of method calls that lead to the method in which the exception was thrown

Example 11-6 Working with an exception object

// try to divide two numbers

// handle possible exceptions

public void TestFunc( )

Trang 23

// most derived exception type first catch (System.DivideByZeroException e) {

Console.WriteLine(

"DivideByZeroException!" + e); }

// do the division if legal

public double DoDivide(double a, double b) {

Open file here

DivideByZeroException! Msg: Attempted to divide by zero HelpLink: http://www.libertyassociates.com

Here's a stack trace:

at ExceptionObject.Test.DoDivide(Double a, Double b)

in c:\ exception06.cs:line 56

at ExceptionObject.Test.TestFunc( )

in exception06.cs:line 22

Close file here.

Example 11-6 Working with an exception object (continued)

Trang 24

In the output, the stack trace lists the methods in the reverse order in which theywere called; that is, it shows that the error occurred inDoDivide( ), which was called

byTestFunc( ) When methods are deeply nested, the stack trace can help you stand the order of method calls

under-In this example, rather than simply throwing aDivideByZeroException, you create anew instance of the exception:

DivideByZeroException e = new DivideByZeroException( );

You don’t pass in a custom message, and so the default message will be printed:

DivideByZeroException! Msg: Attempted to divide by zero.

You can modify this line of code to pass in a default message:

new DivideByZeroException(

"You tried to divide by zero, which is not meaningful");

In this case, the output message will reflect the custom message:

DivideByZeroException! Msg:

You tried to divide by zero, which is not meaningful

Before throwing the exception, set theHelpLink property:

Trang 25

Chapter 12

CHAPTER 12

When a head of state dies, the president of the United States typically doesn’t havetime to attend the funeral personally Instead, he dispatches a delegate Often, thisdelegate is the vice president, but sometimes the VP is unavailable, and the presidentmust send someone else, such as the secretary of state or even the first lady Hedoesn’t want to “hardwire” his delegated authority to a single person; he might dele-gate this responsibility to anyone who is able to execute the correct internationalprotocol

The president defines in advance what responsibility will be delegated (attend thefuneral), what parameters will be passed (condolences, kind words), and what value

he hopes to get back (good will) He then assigns a particular person to that gated responsibility at “runtime” as the course of his presidency progresses

dele-Events

In programming, you are often faced with situations where you need to execute aparticular action, but you don’t know in advance which method, or even whichobject, you’ll want to call upon to execute it The classic example of this is themethod called to handle a button press, a menu selection, or some other “event.”

An event, in event-driven programming (like Windows!), is when something

hap-pens—often as a result of user action, but at times as a result of a change in systemstate or a result of a message begin received from outside the system (e.g., via theInternet)

You must imagine that the person who creates a button (or listbox or other control)

will not necessarily be the programmer who uses the control The control inventor

knows that when the button is clicked, the programmer using the button will wantsomething to happen, but the inventor can’t know what!

Ngày đăng: 07/07/2014, 05:20

🧩 Sản phẩm bạn có thể quan tâm