Thursday, October 07, 2004 - Posts

Code Review with a focus on Performance: Part 2

This is part 2 of a 3-part posts I am writing on reviewing code with a focus on performance. Part 1 is here.

1. There is no check for the Page.IsPostBack property in the Page_Load event [C# / VB.NET]


The Page_Load event is always executed, even during post backs. Use the value of the Page.IsPostBack property to alter the logic during the initial form load and post backs. For instance, controls with the MaintainState attribute set to true should not be reloaded in the Page_Load event in response to a postback.

If necessary, add an If block to the Page_Load event to conditionally load controls.

[C#]
void Page_Load() 
    {
    if (!IsPostBack) {
        // Validate initially to force asterisks
        // to appear before the first roundtrip.
        Validate();
        LoadControls();
       }
    }

2. Test for empty string [C# / VB.NET]

This code is testing a string by comparing it to an empty string (""). String comparisons tend to be slow, and using this method requires additional overhead.

In Visual Basic.NET, test a string's length instead of testing for an empty string by comparing it to "". For example, the following code executes more efficiently:

If Len(strSomeString) <> 0 Then
   
'perform operations on strSomeString
End If

or

If strSomeString.Length <> 0 Then
    'perform operations on strSomeString
End If

instead of:

If strSomeString <> "" Then
    'perform operations on strSomeString
End If

or

If strSomeString <> String.Empty Then
    'perform operations on strSomeString
End If

In Visual C# .NET, compare a string using the Length property instead of testing for an empty string by comparing it to " ". For example, the following code executes more efficiently:

if (strSomeString.Length != 0)
{
    'perform operations on strSomeString
}

rather than:

if (strSomeString != "")
{
    'perform operations on strSomeString
}

or:

if (strSomeString != String.Empty)
{
    'perform operations on strSomeString
}


3. Redim of array found [VB.NET]


It is generally more expensive from a performance perspective to redimension arrays than it is to get more than you need up front. Redimensioning arrays requires Visual Basic .NET to:

  • Allocate space for the new array
  • Copy the data from the old array into the new array, if you have used the Preserve modifier to protect the contents of the array

Dim a larger array until you are finished filling the array, and then Redim to the correct size. A better solution is to use the ArrayList class in the System.Collections namespace.


4. Use New keyword instead of CreateObject [VB.NET]

Using the
New keyword allows for early binding, whereas CreateObject
can perform late binding. Early binding improves the performance of your application. It allows access to member lists and syntax help pop-up windows.

If possible, convert CreateObject calls to use the New keyword.


5. Disable view state on pages if not required [HTML]

View state is enabled by default. The overhead of additional data required to maintain view state should be avoided when the page will not be posted back to itself.

Add the EnableViewState="false" attribute to the Page directive. Alternatively, set the EnableViewState property on individual controls that do not need their view state preserved.


6. Implementation of some form of caching on Web User Control [HTML]

If a page has any static content or content that does not change often, consider using one of several caching methods to improve response time.

There are several methods of cache available. Research the method that is right for your application.


7. Turn off Debug attribute on Web User Control [HTML]

Enabling debugging on a Web form will lower the performance of the page.
Remove the Debug="true" attribute from the Page directive.


8
. Cache attributes set for Page level for Web page requiring query string parameters [C# / VB.NET/ HTML]


The
OutputCache directive in the .ASPX file is set for page level caching (via the VaryByParam="None"
attribute setting). However, the code-behind file is accessing query string values. This situation indicates that the caching level is not set to its optimal value. The page level caching will not be effective because there are query string parameters on this Web page.

Consider changing the VaryByParam="None" to specifically name the parameters that are used to make this page unique. This will allow the caching mechanism to store data for each unique version of the Web page.


9. System.IDisposable.Dispose methods call System.GC.SuppressFinalize [C# / VB.NET]

A type implements IDisposable.Dispose, has a finalizer, and IDisposable.Dispose does not call System.GC.SuppressFinalize.

The Dispose method is implemented to allow users to release resources any time prior to the object becoming available for garbage collection. If the Dispose method is called, it frees the object's resources, making finalization unnecessary. Dispose should call GC.SuppressFinalize so the garbage collector does not call the object's finalizer.

To fix a violation of this rule, add a call to GC.SuppressFinalize to the Dispose method.

The following example shows a method that satisfies this rule.

[C#]
using System; 
namespace UsageLib
{
    public class  TypeA :IDisposable
    {
        // Assume this type has some unmanaged resources.
        private bool disposed = false;
        protected virtual void Dispose(bool disposing) 
        {
            if (!disposed) 
            {
                // Dispose of resources held by this instance.
                // (This process is not shown here.)
                // Set the sentinel.
                disposed = true;
   
                // Suppress finalization of this disposed instance.
                if (disposing)
                {
                    GC.SuppressFinalize(this);
                }
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }

        // Disposable types implement a finalizer.
        ~TypeA()
       
{
            Dispose(false);
        }
    }
}


10. Calling the GC.Collect method [C# / VB.NET]

If the
GC.Collect
method is called in the garbage collection class, it will pause the application while this function operates. Another side effect is that the current objects in Generation 0 will be promoted to Generation 1, at the very least. This will most likely promote short lived objects to a higher generation, thus keeping them around in memory longer than is necessary. It is not recommended that you explicitly call this method in your code.

If possible, do not call this method. Instead, allow the Garbage Collector (GC) to run independently.


11. Switch statement found [VB.NET]

The Switch() function was found. This function does not use short-circuiting when evaluating the argument list. This can cause poor application performance.

Consider using an If-Then-Else or Select-Case construct instead of the Switch() function.


12. Choose statement found [VB.NET]

The
Choose()
function was found.

As an alternative, replace Choose() with another conditional system, such as Select Case, For Next, or Do Loop, to increase performance.

with 6 Comments