Tips & Tricks
Get the Most Out of .NET
Digg This!
Here are some tips on how to improve the performance of your .NET applications.
Use the StringBuilder Object Instead of Concatenation
In the old Visual Basic 6 world, string manipulation was a performance issue that many developers spent time dealing with. In the .NET Framework, the StringBuilder (System.Text.StringBuilder) class is provided to greatly enhance the performance of string manipulation. String concatenation is a very easy task, but it can hurt the performance of your applications. Whenever you make a string modification (be it adding or removing characters or anything else) to the base string data type, a new string is created. The StringBuilder class solves this problem, as shown in Listing 1.
Use the for Loop for String Iteration
Referring to Listing 1, if you want to iterate through your
one-million-character string, using a for loop will be faster than using a
foreach loop. Although the JIT is prohibited from optimizing bounds-checking
in a foreach loop, it is allowed to do such things in a for loop, as shown
in Listing 2.
Speed Up Remoting with Chunky Calls
When dealing with a distributed environment, make sure you consider the
cost of marshaling, which is loosely defined as the process of passing data
between tiers in your distributed architecture.
Consider the code in Listing 3, which is a definition of a class, User,
followed by a console application that calls it.
While this is very good code for a nondistributed application, in a
distributed application it would require several round-trips to set the
properties and call the method. A better idea would be to make the
properties into arguments for the GetUserName method. Listing 4 shows how to
use a chunky call. When the first and last names are passed as parameters,
only one round-trip is made, which results in faster performance.
Use Structs Instead of Classes Where Possible
When defining a simple type, use a struct instead of a class. Since a
struct is a ValueType, it requires much less overhead than declaring an
object (a class). This advantage is limited, however. If the struct you are
defining needs to be boxed (converted to a reference type) just once, the
performance gain is all but lost. So be careful!
In C# Control Integer-Overflow Checking
C# disables integer-overflow checking by default, while VB.NET does the
opposite and enables it by default. When you leave this option disabled, you
run the risk of silent overflow. In C# you can use the checked keyword to
selectively enable the overflow check in certain code. Here is an example:
private int ReturnNumber(int i, int j)
{
checked
{
return i * j;
}
}
Use Jagged Instead of Multidimensional Arrays
If you need to store multidimensional data (like a 2-D table-like
array), consider using a jagged array instead. A jagged array is an
"array-of-arrays;" if you use a jagged array of one-dimensional arrays, your
code will run much faster. The reason is that the JIT compiler produces much
more efficient code for one-dimensional arrays than for multidimensional
arrays, and jagged arrays take up less memory than multidimensional arrays.
Throw Fewer Exceptions
Be careful setting up your code when it comes to exceptions. Writing
code that properly throws and responds to exceptions is very important, but
try not to design your code to throw exceptions when you don't have to.
Consider the example shown in Listing 5.
If the two methods are called many times, the method that returns a
value is much faster. Of course, it also returns less information about what
went wrong, so consider your specific situation before deciding which
approach to use. Note: This does not mean that you should have fewer
try...catch blocks in your code! The try...catch block has very little overhead,
unless an exception is thrown. It is good practice to use try...catch for your
structured exception handling; just make sure that you minimize the number
of exceptions thrown.
Use DataReader over DataSet
When handling data, try to use the DataReader whenever possible. The
DataReader is a stateless stream that allows you to read the data as it
arrives and then drop the data without storing it for further use. While
there are many instances where you need to use a DataSet to cache your data
for use at a later time, make sure that when you don't, you use a DataReader
instead. The only exception to this rule is when you are using Remoting, in
which case the DataSet is usually the proper choice since it marshals much
better.
Use Care with Dynamic Connection Strings
Many developers like to use connection strings in their code rather than
data sources or other methods of connecting to databases. However, if your
connection strings are not identical, it affects connection pooling, which
is a valuable performance function. Connection pooling will create a pool
for each unique connection string, so even if your connection strings are
connecting to the same database, if there is a difference between them, the
connections will not be reused. Storing the connection string in one place
(like a .config file or the registry) helps ensure that the connection
string is exactly the same every time a connection is opened. If you decide
to store the connection string in a .config file, consider encrypting it so
that it is not easily readable by attackers.
Use P/Invoke Instead of COM Interop
When calling unmanaged code, try to use P/Invoke instead of COM Interop
if you can. For example, if you have an ActiveX DLL that was built in VB6,
and you wish to call methods from that DLL, you have two choices.
1. Load the DLL as a COM Reference, thereby telling the compiler to use
COM Interop to load and call it.
2. Use P/Invoke, meaning add a DLLImport attribute to your code that
references the DLL, then add the function headers that are applicable to
your application.
P/Invoke takes as little as eight instructions without marshaling. If
you need to marshal data, it takes 31 instructions plus marshaling. COM
Interop takes 65 instructions plus marshaling.
In C# Use the as Operator
The is operator is used to ask an object if it supports the specified
interface, returning true if it does, false if not. If the result is true,
then it is safe to cast the object. However, when the cast is done, the MSIL
function castclass is called, which also tests to make sure the cast is
valid. In effect, the test is done twice. The as operator combines the is
and cast operations by testing first to see whether a cast is valid (i.e.,
whether an is test would return true) and then completes the cast if it is.
If the cast is not valid (the is test would be false), the as operator
returns null.
C#
// slower
if (myObj is INamingContainer)
{
INamingContainer myNC = (INamingContainer) myObj;
}
// faster
INamingContainer myNC = myObj as INamingContainer;
if (myNC != null)
// cast was successful
Obviously, there will be times when you will want to test the type of an
object but not immediately cast it, which is what makes the is operator
valuable. But in situations where you don't really need to do this test, use
the as operator instead.
Load Assemblies into the GAC
An easy way to speed up loading an assembly is to sign the assembly with
the publisher's key and store it in the Global Assembly Cache (GAC). When a
.NET application calls an external assembly for the first time, the Common
Language Runtime (CLR) must locate the assembly, and the GAC is the first
place the CLR looks for it. Additionally, because only the administrator can
access the GAC, the CLR verifies the assembly's integrity only when the
assembly is installed. Conversely, the CLR verifies assemblies stored
outside the GAC each and every time the assembly is loaded.
Use perfmon to Track Performance
The Performance Monitor, or perfmon, is a great tool to use to track
your application's performance. Many performance counters are available that
will help you trace the execution of your application and identify trouble
spots. Once you have built your application, run it while using perfmon in
the background, then inspect the results.
About James HoranJames Horan is an independent consultant in the Philadelphia area. He is currently using Microsoft .NET technology to provide solutions for manufacturing clients. He also runs www.dotNetGenius.com.