The .NET Framework class library is vast and sometimes
overwhelming. As with any development language there are numerous ways to solve
a problem, but some methods are better than others. I’ll examine a few areas
where performance may be improved by using a set approach.

When to throw an exception

Exception handling is a key aspect of .NET development. It
allows you to easily and gracefully recover from errors that could easily crash
an application, but they can be expensive in terms of system resources. For
this reason, you should exercise restraint when using exceptions in your
applications.

Now, the number of try/catch blocks within your code does
not indicate the number exceptions generated by the code. The catch block is
only executed when an actual exception is encountered. Also, exceptions should
not be used to control program flow. I’ve seen developers throw exceptions to
abort a loop, like the following C# sample:

classExceptionTestClass {
static void Main(string[] args) {
try {
for (int x=0; x < 100; x++) {
if (x == 50) throw new Exception();
} }
catch {}
} }

Notice that the catch block does nothing so program
execution continues. The proper way to address this situation is by using a
break statement:

classExceptionTestClass {
static void Main(string[] args) {
try {
for (int x=0; x < 100; x++) {
if (x == 50) break;
}  }
catch {}
} }

Here’s the equivalent approach in VB.NET:

Sub Main()
Dim x As Integer
Try
For x = 0 To 99
If (x = 50) Then
Exit For
End If
Next x
Catch
End Try
End Sub

Microsoft does include the perfmon
tool that may be used to monitor the exceptions thrown by an application. It
may surprise you to find that certain areas of your application throw more
exceptions than you expected. For better granularity, you can also check the
exception number programmatically by using Performance Counters.

Working with strings

When a string is altered, the original string is garbage
collected with a new object created to hold the changed string. This may not be
an issue for a small number of changes, but an excessive number can tax the
system.

As with Java, the .NET Framework includes a special class to
be used when manipulating string objects: StringBuilder.
The StringBuilder class includes methods for altering
its contents. It is contained in the System.Text
namespace. The following VB.NET sample shows it being used.

Imports System.Text
Module MainModule
Sub Main()
Dim temp As StringBuilder
temp.Append("TechRepublic")
temp.Append(".net")
temp.Replace(".net", ".com")
temp.Append(" rules!")
Console.WriteLine(temp.ToString())
End Sub
End Module

And here’s the C# equivalent:

using System.Text;
namespace Builder {
class SBClass1 {
static void Main(string[] args) {
StringBuilder temp = new StringBuilder();
temp.Append("TechRepublic");
temp.Append(".net");
temp.Replace(".net", ".com");
temp.Append(" rules!");
Console.WriteLine(temp.ToString());
} } }

There are a few tradeoffs. There is overhead associated with
creating a StringBuilder object, both in time and
memory. On a machine with fast memory, a StringBuilder
becomes worthwhile if you’re doing about five operations. As a rule of thumb, I
would say 10 or more string operations are a justification for the overhead on
any machine, even a slower one.

Working with databases

It is important to use the appropriate data provider when
connecting to a database. For example, you should use the SQL managed provider
rather than the ODBC provider. Likewise, you should use the proper provider
when working with other systems like MySQL, Oracle,
DB2, and so forth. Using a generic provider like ODBC introduces another layer
of complexity that will slow down data operations.

Another often cited issue is knowing
when to use DataReader as opposed to DataSet objects. As a rule, if you don’t need the data once
it has been read then use a DataReader.
The DataReader offers a forward-only trip through
data, whereas DataSet allows you access to a group of
data that may be necessary to populate an ASP.NET Repeater or similar control.

On the database side, you should use stored procedures whenever
possible. This puts the processing load on the database server. Set up stored
procedures to handle inserts, updates, and deletes with the data adapter. Stored
procedures do not have to be interpreted, compiled, or even transmitted from
the client. In addition, they cut down on both network traffic and server
overhead.

Take out the trash

While the garbage collector is an excellent feature of the
.NET Framework, it often needs help to determine when an object is ready for
garbage collection. You can provide help by calling the Dispose method whenever
it is available on objects as soon as possible. On the same note, you should
not reference objects once they are no longer needed. The reason is the garbage
collector will not process them if they are referenced.

Performance matters

The performance factor will increase with the size of an
application. The few items covered in this article may not prove useful in a
small program, but as your program grows, these items will be useful for
streamlining application performance. On the other hand, you should keep these
issues in mind during initial development so tweaking performance will not be
such an issue down the road.

TechRepublic’s free .NET newsletter, delivered each Wednesday, contains useful tips and coding examples on topics such as Web services, ASP.NET, ADO.NET, and Visual Studio .NET. Automatically sign up today!