Sometimes we're coding without putting too much thought in it. It's just one more line of code, an innocent line of code. But how many times have you not found a bug that comes down to fixing a single line of code?
To be more specific, I'd like to say some things about the thoughtless instantiation of objects we all do. When fine tuning the performance of an application, one of the important things to notice is how many objects you create and if you can somehow reduce them. The reason is that objects take up some memory and some CPU cycles from the garbage collector that needs to clean up the mess.
Consider this piece of code:
if (url.ToLower() == "/homepage") {
// Do something clever
}
There are two things wrong here. First, the ToLower method is dependent on the current culture. The Invariant Culture should be prefered instead. Also, according to MSDN, ToUpperInvariant is actually more reliable that ToLowerInvariant so strings should be normalized to uppercase.
But the code does something even worse. It is creating a new string object with that call to ToLower, just to do the equality comparison and throw it away. There's a better way to do it:
if (string.Equals(url, "/homepage", StringComparison.OrdinalIgnoreCase) {
// That's better
}
Since that comparison is case insensitive, you can chose between StringComparison.OrdinalIgnoreCase and StringComparison.InvariantCultureIgnoreCase. The first is supposed to be faster, as it is the old school byte to byte comparison but it might not be appropriate for the problem at hand. You can read more in this stackoverflow discussion. But in any case, you just saved the life of a string object!
Another thing I've seen (and done) is driven by excessive love for syntactic sugar. Well, too much sugar makes you fat and syntactic sugar is no different. I'm talking about objects that implement IDisposable just for the pretty using statement but without themselves owning any unmanaged resources or any other IDisposable. Consider this example:
class MyClass
{
private bool busy;
public void Start()
{
busy = true;
}
public void Stop()
{
busy = false;
}
}
class Program
{
MyClass myClass = new MyClass();
myClass.Start();
// do some work
myClass.Stop();
}
There's some class that the main program is using. There's a Start and a Stop method and some statements in between. The requirement is that the Stop method must always be called, even if an exception occurs in between. If you're thinking "try - finally", then you haven't seen this one:
class MyClass
{
private bool busy;
public void Start()
{
busy = true;
}
public void Stop()
{
busy = false;
}
}
class MyClassHelper : IDisposable
{
private MyClass instance;
public MyClassHelper(MyClass instance)
{
this.instance = instance;
instance.Start();
}
public void Dispose()
{
instance.Stop();
}
}
class Program
{
MyClass myClass = new MyClass();
using (MyClassHelper syntacticSugar = new MyClassHelper(myClass))
{
// do some work
}
}
This is what happens when a C# developer realizes that the using block is a glorified try - finally block and decides it's cool to replace all try - finally blocks with using statements... you can spare the life (and the very class definition) of the MyClassHelper object by using the humble try - finally block and leave the using for the real IDisposables that are releasing COM+ objects, database connections, nuclear reactors, that sort of things. Like this:
class MyClass
{
private bool busy;
public void Start()
{
busy = true;
}
public void Stop()
{
busy = false;
}
}
class Program
{
MyClass myClass = new MyClass();
myClass.Start();
try
{
// do some work
}
finally
{
myClass.Stop();
}
}
Hope this helps.