Quantcast
Channel: Scott Bamford
Viewing all articles
Browse latest Browse all 16

Object.ToStringSafe()

$
0
0

If like me you’ve worked with C# and the .NET framework for years then you will probably have written variations on following code hundreds of time when trying to display values on screen or save values into text based files or SQL statements:

object rawValue = SomeMethodCall();
string displayValue = String.Empty;
if (rawValue != null) {
    displayValue = rawValue.ToString();
}

The code itself is simple enough to get right first time, and easy to read and understand, but after you’ve written it a few dozen times it starts to appear like unwelcome rash across your code. A programmers next natural instinct is to see if there is a way to shorten the code.

Unfortunately the ?? operator can’t help us here unless we are exclusively dealing with strings for rawValue (in which case why are you calling ToString()?). We can however shorten things substantially with the ? operator:

object rawValue = SomeMethodCall();
string displayValue = (rawValue == null? String.Empty: rawValue.ToString());

This has helped and taken our code from five lines to two, and hasn’t noticeably affected readability. But if we are only interested in the displayValue woundn’t it be nicer if we were able to just do:

string displayValue = SomeMethodCall().ToString();

This code will execute fine, but as soon as a null object is returned from SomeMethodCall() we’ll get a NullReferenceException raised and if we didn’t see it in testing, our end users will see an unhandled exception we should never have introduced.

If we try to use the ? operator directly with the method call and the best you can get is:

string displayValue = SomeMethodCall() == null? String.Empty: SomeMethodCall();

You can tell immediately from the code that this would be at best wasteful if not potentially damaging depending on the side effects of SomeMethodCall(). Under normal circumstances, where SomeMethodCall() doesn’t return null, we end up executing SomeMethodCall() twice. If the method accesses a web service or database we will have potentially doubled the impact of the code on the server, and slowed down the user experience.

What can be done then? Should we just put up with the two line of code where one would work? Until recently I would have said yes, but with LINQ usage on the rise I’ve started to see this particular problem causing ugly code to be written for lambda statements, or worse developers knowingly being lazy with their handling of potential null values when calling .ToString()!

We can actually use a little used feature of extension methods to help us with this problem. As you will know extension methods allow us to invoke static utility methods in a syntax that mirrors invoking a member of a class. The compiler understands the code that calls an extension method and effectively re-writes the syntax from a member call to a static method call for us. To get an idea of how this works take a look at my previous post.

Because the member-like syntax is converted into a static method call, it is possible to call the member on a null reference.  Therefore the first line of the following code would throw a NullReferenceException, but if MyExtensionMethod() was an extension method that handled a null specially, the second will not.

((object)null).ToString();
((object)null).MyExtensionMethod();

Using this technique we are able to create extension methods that special case null values, but maintain the readable member-style syntax.

I’m going to throw a strong word of warning in here now. When you add an extension method that does not behave like a member method call, particularly ones that don’t raise a NullReferenceException when called on a null variable you are moving away from basics that programmers take for granted when reading code. Used incorrectly this can make code harder to understand and therefore harder to understand. You should be sure about what you are doing before you add extension methods that expose this non-standard behaviour. Its been my experience that methods that should follow this behaviour are almost always involved with displaying values as strings, or converting values between types to pass to an ORM or similar module.

My personal convention to make sure I can identify where the technique has been used is to suffix the method name with “Safe”, so the call above would be MyExtensionMethodSafe(). If everybody in the team follows this convention when they feel there is a genuine need for the extension method to treat nulls differently to a member method call then the code remains easy to read. Don’t forget however that even if you’ve adopted this convention throughout your team, you will still have to train new people joining the team on the convention.

Now with that warning having been strongly stated, lets return to looking at the problem at hand. In this case I believe it makes very good sense to provide a “Safe” extension method companion to ToString(). Here is the code for the ToStringSafe() extension method in full:

namespace Mvpc.Extensions
{
    public static class ObjectExtensions_ToStringSafe
    {
        public static string ToStringSafe(this object value)
        {
            // Nulls just return empty strings.
            if (value == null) {
                return String.Empty;
            }

            return value.ToString();
        }
    }
}

If you read my post on async extension methods you will already know that I recommend placing any extension method that works on string, object, int, or any of the core types of the .NET Framework under a namespace ending in “Extensions” so they don’t litter the initilisense when the user doesn’t need them. This rule applies here too as the majority of code will not want to use the ToStringSafe() method.

After adding a using for the Mvpc.Extensions namespace it finally becomes simple to write:

string displayValue = SomeMethodCall().ToStringSafe();

We finally get our five lines of oft-duplicated code down to a single readable line.

Since introducing this new method I’ve completely stopped seeing programmers being lazy with their .ToString() handling of nulls inside lambda statements. Hopefully you will see the same too as well as being able to produce more readable null-safe code.



Viewing all articles
Browse latest Browse all 16

Trending Articles