You are on page 1of 4

Never rethrow an exception at the highest point in the exception-han-

dling hierarchy within a thread. Since no exception handlers can catch


this rethrown exception, it will be considered unhandled, and the
thread will terminate after all finally blocks have been executed.

What if you use the ThreadPool and QueueUserWorkItem? This method will still help
you because you added the handling code that will execute inside the thread. Just
make sure you have the finally block set up so that you can notify yourself of excep-
tions in other threads as shown earlier.
In order to provide a last-chance exception handler for your WinForms application,
you need to hook up to two separate events. The first event is the System.AppDomain.
CurrentDomain.UnhandledException event, which will catch all unhandled exceptions
in the current AppDomain on worker threads; it will not catch exceptions that occur
on the main UI thread of a WinForms application. See Recipe 7.13 for more informa-
tion on the System.AppDomain.UnhandledException event. In order to catch those, you
also need to hook up to the System.Windows.Forms.Application.ThreadException,
which will catch unhandled exceptions in the main UI thread. See Recipe 7.13 for
more information about the ThreadException event.

See Also
The “Thread Class” and “Exception Class” topics in the MSDN documentation.

18.4 Being Notified of the Completion of an


Asynchronous Delegate
Problem
You need a way of receiving notification from an asynchronously invoked delegate
that it has finished. This scheme must allow your code to continue processing with-
out having to constantly call IsCompleted in a loop or to rely on the WaitOne method.
Since the asynchronous delegate will return a value, you must be able to pass this
return value back to the invoking thread.

Solution
Use the BeginInvoke method to start the asynchronous delegate, but use the first
parameter to pass a callback delegate to the asynchronous delegate, as shown in
Example 18-3.

Being Notified of the Completion of an Asynchronous Delegate | 727


Example 9-6. Using the ObservableDictionary and ObservableDictionaryObserver
classes (continued)
// hook up the approval events for adding or changing
observer.ApproveAdd +=
new ObservableDictionaryObserver<int, string>.
Approval(SeekApproval);
observer.ApproveChange +=
new ObservableDictionaryObserver<int, string>.
Approval(SeekApproval);

// Use the observable instances


obsDict1.Add(1, "one");
obsDict2.Add(2, "two");
obsDict3.Add(3, "three");

// Insure the approval process worked


Debug.Assert(obsDict1.Count == 1);
Debug.Assert(obsDict2.Count == 1);
// this should be empty as the value was more than three characters
Debug.Assert(obsDict3.Count == 0);

// Unregister the observable instances


observer.Unregister(obsDict3);
observer.Unregister(obsDict2);
observer.Unregister(obsDict1);

///////////////////////////////////////////////////////////////
// Now do it with a different type of dictionary
///////////////////////////////////////////////////////////////
// Create two observable SortedList instances
SortedList<string, bool> sortedList1 = new SortedList<string, bool>( );
SortedList<string, bool> sortedList2 = new SortedList<string, bool>( );

var obsSortedList1 = sortedList1.MakeObservableDictionary( );


var obsSortedList2 = sortedList2.MakeObservableDictionary( );

// Create an observer for the two subject objects


ObservableDictionaryObserver<string, bool> listObserver =
new ObservableDictionaryObserver<string, bool>( );

// Register the three subjects with the observer


listObserver.Register(obsSortedList1);
listObserver.Register(obsSortedList2);

// hook up the approval events for adding or changing


listObserver.ApproveAdd +=
new ObservableDictionaryObserver<string, bool>.
Approval(ApprovePositive);
listObserver.ApproveChange +=
new ObservableDictionaryObserver<string, bool>.
Approval(ApprovePositive);

// Use the observable instances

342 | Chapter 9: Delegates, Events, and Lambda Expressions


Console.WriteLine( );
List<Match> results = FindEachOccurrenceOf
("one one two three one two three one "
+ " two three one two three", "one", 2);
foreach (Match m in results)
Console.WriteLine(m.ToString( ) + "\t" + m.Index);
}

Discussion
This recipe contains two similar but distinct methods. The first method,
FindOccurrenceOf, returns a particular occurrence of a regular expression match. The
occurrence you want to find is passed in to this method via the occurrence parame-
ter. If the particular occurrence of the match does not exist—for example, you ask to
find the second occurrence, but only one occurrence exists—a null is returned from
this method. Because of this, you should check that the returned object of this
method is not null before using that object. If the particular occurrence exists, the
Match object that holds the match information for that occurrence is returned.
The second method in this recipe, FindEachOccurrenceOf, works similarly to the
FindOccurrenceOf method, except that it continues to find a particular occurrence of
a regular expression match until the end of the string is reached. For example, if you
ask to find the second occurrence, this method would return a List<Match> of zero or
more Match objects. The Match objects would correspond to the second, fourth, sixth,
and eighth occurrences of a match and so on until the end of the string is reached.

See Also
The “.NET Framework Regular Expressions” and “ArrayList Class” topics in the
MSDN documentation.

10.10 Using Common Patterns


Problem
You need a quick list from which to choose regular expression patterns that match
standard items. These standard items could be a social security number, a zip code, a
word containing only characters, an alphanumeric word, an email address, a URL,
dates, or one of many other possible items used throughout business applications.
These patterns can be useful in making sure that a user has input the correct data
and that it is well formed. These patterns can also be used as an extra security mea-
sure to keep hackers from attempting to break your code by entering strange or mal-
formed input (e.g., SQL injection or cross-site-scripting attacks). Note that these
regular expressions are not a silver bullet that will stop all attacks on your system;
rather, they are an added layer of defense.

Using Common Patterns | 389


The Split method is case-sensitive. To split a string on the letter a in a case-
insensitive manner, use code like the following:
string[] discreteInfo = delimitedInfo.Split(new char[] {'a', 'A'});

Now, anytime the letter a is encountered, no matter what its case, the Split method
views that character as a delimiter.

See Also
The “String.Join Method” topic in the MSDN documentation.

2.15 Iterating over Each Character in a String


Problem
You need to iterate over each character in a string efficiently in order to examine or
process each character.

Solution
C# provides two methods for iterating strings. The first is the foreach loop, which
can be used as follows:
string testStr = "abc123";
foreach (char c in testStr)
{
Console.WriteLine(c.ToString( ));
}

This method is quick and easy. Unfortunately, it is somewhat less flexible than the
second method, which uses the for loop instead of a foreach loop to iterate over the
string. For example:
string testStr = "abc123";
for (int counter = 0; counter < testStr.Length; counter++)
{
Console.WriteLine(testStr[counter]);
}

Discussion
The foreach loop is simpler and thus less error-prone, but it lacks flexibility. In
contrast, the for loop is slightly more complex, but it makes up for that in flexibility.
The for loop method uses the indexer of the string variable testStr to get the
character located at the position indicated by the counter loop index. Care must be
taken not to run over the bounds of the string array when using this type of looping
mechanism.

64 | Chapter 2: Strings and Characters

You might also like