What is Optimization?
The word Optimization is derived from the Latin word Optimal which means the best. Optimization is a methodology of making a system or decision fully perfect, functional, and effective.
Now, what is code Optimization?
In terms of code, Optimization is the process of modifying code in such a way that enhances its performance, improves code quality, and makes it as efficient as possible. It requires an aspect of writing an efficient C# .Net-based application.
Need of Optimized code
A program should be optimized so that it:
- Becomes a smaller size.
- Consumes less memory.
- Faster execution.
- Performs fewer input/output operations.
Following are some of the techniques that help to enhance the speed and efficiency of C# code and applications:
- Replace ArrayList with List<>
ArrayList is beneficial when we store multiple types of objects within the same list.
But if we want to store the same type of data in one ArrayList, then we should prefer using List<> objects instead of to gain more performance.
Example: In the above code, it only contains a string (Student name). It also requires typecasting. Using the List<> class is much better in this case.
Here we are using List<> for storing student names. Now, there is no need for typecasting.
- Check for empty strings
In C#, we use code like this to check if a string is empty.
This line of code does work but it is considered a bad practice.
Instead of this, we should use string. Empty that will enhance the performance of code.
- For vs foreach
There are two alternative ways of iterating over a list of items i.e For and foreach loop.
These both loops work in a different way.
The for loop first loads all items of a list in memory and then use an indexer to iterate over each element. On the other side, foreach loop uses an enumerator and iterates until it reaches the end of the list.
For better performance, use for loop for ArrayList and Generic collections, and for typed array, we can use any loop.
- Eager vs Lazy loading
There are two concepts used in ORM frameworks. Lazy and Eager loading. Do not use lazy loading if you do not need it specifically as fetching related data costs more. On the other hand, do not be too generous while using eager loading. It is not a good practice to load the whole database for one record. It would be better to make your calculations better and then use them wisely.
- Avoid unnecessary boxing and unboxing
If we talk about performance, then boxing and unboxing are expensive processes like garbage collection. We should avoid using them unnecessarily.
Boxing is converting a value type to an object type or to an interface type.
Unboxing is the opposite – converting object type into a value type.
When we box a value, it creates another object on the heap which puts pressure on garbage collection.
To avoid boxing and unboxing, we can prefer using generic collections such as System.Collections.Generic.List<T> over System.Collections.ArrayList
- Beware of string concatenation
In C#, strings are immutable. When we perform string operations like replace, substring or concatenation, it is creating a new string which increases memory space. Better avoid concatenating a large number of strings inside a loop. Use System.Text.StringBuilder class instead of using the “+” operator. It will not create new instances for the concatenation of every string.
- Use && And || Operators
If you are using if statements, make sure to use the double-and notation (&&) and/or
the double-or notation(||).
If statements that use & and | check every part of the statement and then apply the “and” or “or” whereas && and || check through the statements one at a time and stop whether the condition is true or false.
In the above line of code, if object1 is null, then it won’t execute object1.run() method.
But if you are using & operator here, object1.runMethod() will be called even if object1 is null which will cause an exception.
- Exception Handling
Exception handling matters the most in measuring the performance of an application.
Improper handling of exceptions decreases the performance of code.
There are few points one must consider while dealing with exceptions:
- Always prefer a specific exception type that can catch the exception for the code written in the method. Avoid using the Exception type for all cases.
- Add a meaningful message while throwing an exception so that the user knows where that exception has occurred instead of going through the stack trace.
- Avoid using try-catch block in deeply nested code. It will slow down the performance of the code.
- It is a good practice to throw exceptions rather than returning the custom messages or error codes and handle them in the main calling method.
- Always check the inner exception and read the exception message or stack trace while logging exceptions. It gives the actual point in the code where the error is thrown.
Finally: simplify your code. Go through every statement and check what might be unnecessary. Refactor code. This can really help in increasing the overall performance of code.