Wednesday 25 January 2012

Optimize Code C#

1. Knowing when to use StringBuilder

You must have heard before that a StringBuilder object is much faster at appending strings together than normal string types.
The thing is StringBuilder is faster mostly with big strings. This means if you have a loop that will add to a single string for many iterations then a StringBuilder class is definitely much faster than a string type.
However if you just want to append something to a string a single time then a StringBuilder class is overkill. A simple string type variable in this case improves on resources use and readability of the C# source code.
Simply choosing correctly between StringBuilder objects and string types you can optimize your code.

2. Comparing Non-Case-Sensitive Strings

In an application sometimes it is necessary to compare two string variables, ignoring the cases. The tempting and traditionally approach is to convert both strings to all lower case or all upper case and then compare them, like such:
str1.ToLower() == str2.ToLower()
However repetitively calling the function ToLower() is a bottleneck in performace. By instead using the built-in string.Compare() function you can increase the speed of your applications.
To check if two strings are equal ignoring case would look like this:
string.Compare(str1, str2, true) == 0 //Ignoring cases
The C# string.Compare function returns an integer that is equal to 0 when the two strings are equal.

3. Use string.Empty

This is not so much a performance improvement as it is a readability improvement, but it still counts as code optimization. Try to replace lines like:
if (str == "")
with:
if (str == string.Empty)
This is simply better programming practice and has no negative impact on performance.
Note, there is a popular practice that checking a string's length to be 0 is faster than comparing it to an empty string. While that might have been true once it is no longer a significant performance improvement. Instead stick with string.Empty.

4. Replace ArrayList with List<>

ArrayList are useful when storing multiple types of objects within the same list. However if you are keeping the same type of variables in one ArrayList, you can gain a performance boost by using List<> objects instead.
Take the following ArrayList:
ArrayList intList = new ArrayList();
intList.add(10);
return (int)intList[0] + 20;
Notice it only contains intergers. Using the List<> class is a lot better. To convert it to a typed List, only the variable types need to be changed:
List<int> intList = new List<int>();

intList.add(10)

return intList[0] + 20;
There is no need to cast types with List<>. The performance increase can be especially significant with primitive data types like integers.

5. Use && and || operators

When building if statements, simply make sure to use the double-and notation (&&) and/or the double-or notation (||), (in Visual Basic they are AndAlso and OrElse).
If statements that use & and | must check every part of the statement and then apply the "and" or "or". On the other hand, && and || go thourgh the statements one at a time and stop as soon as the condition has either been met or not met.
Executing less code is always a performace benefit but it also can avoid run-time errors, consider the following C# code:
if (object1 != null && object1.runMethod())
If object1 is null, with the && operator, object1.runMethod()will not execute. If the && operator is replaced with &, object1.runMethod() will run even if object1 is already known to be null, causing an exception.

6. Smart Try-Catch

Try-Catch statements are meant to catch exceptions that are beyond the programmers control, such as connecting to the web or a device for example. Using a try statement to keep code "simple" instead of using if statements to avoid error-prone calls makes code incredibly slower. Restructure your source code to require less try statements.

7. Replace Divisions

C# is relatively slow when it comes to division operations. One alternative is to replace divisions with a multiplication-shift operation to further optimize C#. The article explains in detail how to make the conversion.

8. Boxing and UnBoxing

Variables that are based on value types directly contain values. Variables of reference types (referred to as objects) store references to the actual data and should be used to define the behavior of your application. On occasion, programmers make method calls passing a value type where a reference type is expected. To handle this situation C# uses boxing. Boxing converts a value type to a reference type and consists of two operations:
  • Allocating an object instance (on the heap).
  • Copying the value-type value into that instance.


The box contains the copy of the value type object and duplicates the interfaces implemented by the boxed value type. When you need to retrieve anything from the box, a copy of the value gets created and returned, called unboxing. That’s the key concept of boxing and unboxing. A copy of the object goes in the box, and another gets created whenever you access what’s in the box. The major issue with boxing and unboxing is that it happens automatically. Every type in C#, including the intrinsic types, is derived from Object and may be implicitly cast to an object. The following code is an example of commonly used constructs that cause boxing operations with value types.

int i = 15;

int j = 25;

Console.WriteLine(“Print values: {0}, {1}”, i, j);

This may seem like a trivial amount of overhead at first glance. However, given enough of these statements scattered throughout your application, you'll soon discover that the overhead quickly becomes substantial. In addition to the heap allocation and copy operation performed when boxing, there's overhead in maintaining the heap-based object, such as reference tracking, heap compaction, and garbage collection. This is what the code looks like to the compiler.

int i = 15;

     int j = 25;

     object obj1 = i;

     object obj2 = j;

     Console.WriteLine("Print values: {0}, {1}", obj1.ToString(), obj2.ToString());

You would never write the code as listed above, but that is what you are doing by letting the compiler automatically convert from a specific value type to System.Object. You could modify the previous code to avoid the implicit boxing and unboxing by using the ToString method as shown below.

Console.WriteLine("Print values: {0}, {1}", i.ToString(), j.ToString());

Using arrays to store a collection of value types is a common area where boxing can hurt application performance. If you intend to work with ArrayList, for example, do not declare your data type as struct (Value type) because ArrayList works with Object (Reference type) and every time you add an instance of the struct or run over the container, in a loop, a boxing process will occur.

9. ‘as’ versus type casting

As good programming practice we try to avoid coercing one type into another when we can. But sometimes, runtime checking is simply unavoidable. When you have to cast an object into another type you have a couple of choices: the as operator or casting. You should use the as operator whenever you can because it is safer and more efficient at runtime.

Using traditional casting you could write something like the following.

object o = new MyObject();

    try

    {

     MyType m;

m = (MyType)o;

if (m != null)

 {

         //work with m as a MyType object

      }

else

     {

         //Report null reference failure

     }

    }

    catch

    {

         //report the conversion failure

    }

Instead we will use the as operator as an alternative and produce simpler and easier to read code.

    object o = new MyObject();

MyType m = o as MyType;

if (m != null)

he as operator is similar to a cast operation; however, there are two advantages to using the as operator.

  •     It makes your code more     readable.    
  •     If a type mismatch occurs,     the object will become null instead of throwing an exception.

Note: Using the as operator instead of casting only works for reference types.

No comments:

Post a Comment