Collection of small but useful extensions methods #1
I’ve done a few posts on some useful extension methods before, but there’s also a bunch of smaller extension methods I wanted to share that didn’t each warrant their own post – so below are some of the small but useful methods I’ve used in the past!
IDictionary – GetValueOrThrow
Dictionaries are great in .NET – they allow super fast key lookups to retrieve a paired value. Sometimes, you’ll try to retrieve the value for a key that doesn’t exist in the dictionary, and you’ll be met with a very generic ‘KeyNotFoundException’. I’ve always wished this would actually include the key that the code attempted to lookup in the error message, as to say it would aid debugging would be an understatement! So I created the below extension method which does include the key in the error message (just be sure that including the key isn’t going to be a security risk if a user sees it!)
public static U GetValueOrThrow<T, U>(this Dictionary<T, U> dict, T key, U defaultValue = default(U)) { U value; if (!dict.TryGetValue(key, out value)) throw new KeyNotFoundException($"Cannot find key {key}"); return value; }
IDictionary – GetValueOrDefault
As a natural counterpart to the first extension method, this one will return a default value if the key doesn’t exist. Very useful, and it avoids having to constantly use awful ‘out’ parameters. Note that if you don’t pass in a default value, the value will simply be the default value of the type – 0 for int, null for reference types.
public static U GetValueOrDefault<T, U>(this Dictionary<T, U> dict, T key,U defaultValue = default(U)) { U value; if (!dict.TryGetValue(key, out value)) return defaultValue; return value; }
String – SafeSubstring
How many times have you had to had to write this boilerplate code when trying to extract a substring?
var extract = input.Length >= 20 ? input.Substring(0,20) : input;
With the below extension method, this becomes a thing of the past!
public static string SafeSubstring(this string input, int start, int length) { if (input == null) throw new ArgumentNullException(nameof(input)); if (input.Length >= (start+ length)) return input.Substring(start, length); return input.Length > start ? input.Substring(start) : string.Empty; }
ASP.NET Control – FindControlOrThrow<T>
This one is specific to ASP.NET WebForms (I shudder when I type that), and helps reduce a bit of the boiler plate code and it reduces the chances of the dreaded ‘Object reference not set to an instance of an object’ error by throwing a meaningful exception if the control could not be found. It also reduces the need to cast the return value, as the type is passed in as a generic argument
public static T FindControlOrThrow<T>(this Control parentControl, string name) where T : Control { if (parentControl == null) throw new ArgumentNullException(nameof(parentControl)); Control controlGeneric = parentControl.FindControl(name); if (controlGeneric == null) throw new Exception($"Cannot find control with name '{name}' in parent '{parentControl.ID}'"); var control = controlGeneric as T; if (control == null) throw new Exception($"Cannot convert control '{name}' of type {controlGeneric.GetType().Name} to type {typeof(T).Name}"); return control; }
Hi,
I’d catch standard exception and throw custom in GetValueOrThrow().
And I’d use the ?? or ?: operators in GetValueOrDefault.
Also you can use LINQ (SelectMany() et al) in FindControlOrThrow(), see this question in Stack Overflow.
Ah very good points. SelectMany is something that has perplexed me for a while but it’s so useful.
Thank you for the post!
If we take a closer look at the SafeSubstring implementation we can notice that it is not really safe in one of the cases. I’m talking about the throw statement when the input is null. Furthermore, there are still cases when it might throw even is the input is not null (start < 0 or length < 0 for example).
There are several cases when it is not possible to implement SafeSubstring without throwing an exception (but then it is not really "safe"). An alternative might be to do something like "bool TrySafeSubstring(this string input, int start, int length, out string substring)" or "(bool success, string substring) SafeSubstring(this string input, int start, int length)"
On a side node, if C# 7.1 is allowed then GetValueOrDefault can be expressed a bit more succinctly:
public static U GetValueOrDefault(this Dictionary dict, T key, U defaultValue = default)
=> dict.TryGetValue(key, out var value) ? value : defaultValue;
I wish C# had a built-in Option (a.k.a Maybe) or Try type then SafeSubstring would have signature like “Option SafeSubsting(this string input, int start, int length)”. In the meantime we could use LanguageExt (https://github.com/louthy/language-ext) or similar library to provide this functionality.
Very nice, C 7.1 I haven’t delved into much (we’re still using Visual Studio 2015 at my job) but I’m eager to give it a go!