Search
Close this search box.

C#/.NET Five Little Wonders That Make Code Better (1 of 3)

We all have those little wonders in our .NET code, those small tips and tricks that make code just that much more concise, maintainable, or performant.  Many of you probably already know of some of these, but many folks either overlook them or just don’t know about them, so this article is a refresher.

I’m planning on making this a three-part series encompassing 15 little wonders that I had thought of, though I’m very curious to hear the little wonders you can think of as well. 

Update: Part 2 is now available here.

Update: Part 3 is now available here.

1.  The Null Coalescing Operator (??)

This one is such an elegant little operator that can be extremely useful in some situations.  How often do you have a variable that you want to use the value of, but if that value is null you want to substitute a default value?  For example, say you wanted to assign a string to a variable, but if that string is null you want the empty string instead?

You could, of course, write an if statement:

string name = value;

if (value == null) {
  name = string.Empty;
}

Or better yet, you could use a ternary operator (?:):

string name = (value != null) ? value : string.Empty;

Ah, that’s much more concise, but we can get even better!  C# adds a null-coalescing operator (??) that is a short-cut for the ternary operator (?:) checking against a null:

string name = value ?? string.Empty;

Very nice and concise!  You can even write a helper method to trim a string and return null if string is all whitespace so that it can be used with “??”.

public static class StringUtility {
  public static string TrimToNull(string source) {
    return string.IsNullOrWhiteSpace(source) ? null : source.Trim();
  }
}

Then the null-coalescing operator can be used to turn completely empty strings into defaults.

string name = StringUtility.TrimToNull(value) ?? "None Specified";

2.  The As Cast

How many times have you seen code like this:

if (employee is SalariedEmployee) {
  var salEmp = (SalariedEmployee)employee;

  pay = salEmp.WeeklySalary;

  // ...
}

This is redundant because you are checking the type twice.  Once in the is check and once in the cast.  Whenever you find yourself going down this path, prefer the as cast.  This handy cast will cast the type if the types are compatible, or return null if not:

var salEmployee = employee as SalariedEmployee;

if (salEmployee != null) {
  pay = salEmployee.WeeklySalary;

  // ...
}

The code reads better without the ugly cast, and you avoid double-checking the type.

3.  Auto-Properties

We all know about C# properties, and most of us know about auto properties.  They turn code like these two typical properties with backing fields:

public class Point {
  private int _x, _y;

  public int X {
    get { return _x; }
    set { _x = value; }
  }

  public int Y {
    get { return _y; }
    set { _y = value; }
  }
}

Into a much more concise and maintainable piece of code:

public class Point {
  public int X { get; set; }
  public int Y { get; set; }
}

Much shorter!  Whenever you have a simple property that just gets/sets a backing field, you should favor the auto-properties if nothing else for saving a lot of typing!  All you need is write the properties with no get/set body and the C# compiler will automatically generate a field for you behind the scenes.

To make things even more fun, you can make auto-properties with asymmetrical access levels!  That is, you can make an auto-property “read-only” or “write-only”.  That is, you can make the get public and the set private or vice versa.

public class Asymetrical {
  public string ThisIsReadOnly { get; private set; }

  public double ThisIsWriteOnly { private get; set; }
}

This makes it easy to make auto-properties that can be set only by the class itself but read publically and vice-versa (though, in practice write-only properties are rarely useful).

4.  The Stopwatch Class

How many times have you wished to log how long a particular piece of code took to execute?  Maybe you are trying to track average request time or some such metric, or maybe send a warning message when a stored procedure takes longer than 1 second to execute.

Well, you could do it with DateTime like so:

DateTime start = DateTime.Now;
SomeCodeToTime();
DateTime end = DateTime.Now;
Console.WriteLine("Method took {0} ms", (end - start).TotalMilliseconds);

But DateTime is imprecise for this sort of metric.  You could also query the high resolution timer using Win32 API calls via PInvoke, but this is also very messy and more error prone.

So what’s a C# developer to do?  Enter the Stopwatch class which is in the System.Diagnostics namespace.  The Stopwatch class makes it clean and easy to use the high resolution timer through the convenience of a C# class:

var timer = Stopwatch.StartNew();
SomeCodeToTime();
timer.Stop();
Console.WriteLine("Method took {0} ms", timer.ElapsedMilliseconds);

Much more precise and very clean.  Note there is a static factory method to create a Stopwatch and immediately start it.  You also have the option of creating using new and then starting manually as you choose.

TimeSpan factory methods

How many time have you seen a piece of code like this and wondered how long the Sleep was going to before?

Thread.Sleep(50);

Now, is that 50 seconds? Milliseconds?  It is milliseconds, actually, but what if you ran across something like this in someone’s code:

void PerformRemoteWork(int timeout) { ... }

What is this timeout?  Seconds?  Minutes?  Milliseconds?  It all depends on the developer!  I’ve seen timeouts and intervals in both the BCL and custom code written as either seconds or milliseconds.  It’s almost always better to use TimeSpan since it makes it far less ambiguous:

void PerformRemoteWork(TimeSpan timeout) { ... }

Now, we don’t need to worry about units because that’s specified when the user constructs the TimeSpan:

PerformRemoteWork(new TimeSpan(0, 0, 0, 0, 50));

The disambiguates things from the standpoint of the method itself, but not for the caller!  Is the caller passing 50 seconds?  Milliseconds?  It seems we have a similar issue!  This is somewhat confused further by the fact that there are 5 constructs for TimeSpan and they are not all consistent:

TimeSpan();
TimeSpan(long ticks);
TimeSpan(int hours, int minutes, int seconds);
TimeSpan(int days, int hours, int minutes, int seconds);
TimeSpan(int days, int hours, int minutes, int seconds, int milliseconds);

Notice how the 3-int constructor is hours minutes seconds, and the 4-int constructor adds days?  If you want to specify milliseconds, you need the 5-int constructor.  This can be confusing because reading a 4-int constructor may look like hours/seconds/minutes/milliseconds but it’s not.

Enter the TimeSpan static factory methods.  These allow you to construct TimeSpans unambiguously:

PerformRemoteWork(TimeSpan.FromMilliseconds(50));

Now there’s no ambiguity and it’s perfectly readable!  No chance of misconstruing the parameters.  There’s also:

TimeSpan.FromDays(double days);
TimeSpan.FromHours(double hours);
TimeSpan.FromMinutes(double minutes);
TimeSpan.FromSeconds(double seconds);

So you can easily specify an interval in an unambiguous way.  It even works with static readonly fields:

public sealed class MessageProducer {
  private static readonly _defaultTimeout = TimeSpan.FromSeconds(30);
  ...
}

Summary

I hope you enjoyed these five little wonders, I have a stack more to introduce next week.  Hopefully you found one you didn’t know about or had forgotten about and can put it to good use!

Tweet Technorati Tags: C#,.NET,TimeSpan,DateTime,??,Automatic Properties

This article is part of the GWB Archives. Original Author:  James Michael Hare

Related Posts