(+N) Consulting Inc.

Consulting. Software solutions. Training.

Between - Extension method to shorten notation

Sometimes I just write code. And sometimes I clean up my code. Most of the times, I focus on the meat of the methods, hacking away at verbose or lengthy flows, re-factoring out common code, trying to untangle overly complex logic etc. Recently, I noticed that many of the conditional terms I write span very long lines and are a bit cumbersome to read. The reason for that is that many of the variable names are long, or the properties or both and that often the comparison is on a property of an object or member of a collection etc. So for instance: if (summerCatalog.Products[0].ProductCategories[0].ParentCategoryID >= 1 && summerCatalog.Products[0].ProductCategories[0].ParentCategoryID <= 4) { //... } Can become quite long. Long is not easy to read. Long is not easy to maintain. Long is not easy to think through. What I really wanted to say is if [value] is between [a] and [b]. Of course, one could say "lets just make the variable names shorter". But that flies in the face of self explanatory plain naming. So abbreviating for the sake of short-lineliness (New word! You heard it her first!) is out. Well, this is just screaming "EXTENSION METHODS" doesn't it? Here we go then: /// <summary> /// Returns whether the value is between the 2 specified boundaries. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="value">The value to compare</param> /// <param name="minValueInclusive">The min value (inclusive).</param> /// <param name="maxValueInclusive">The max value (inclusive).</param> /// <returns>True if the value is equal to or between the boundaries; False otherwise.</returns> public static bool Between<T>(this T value, T minValueInclusive, T maxValueInclusive) where T : IComparable<T> { if (minValueInclusive.CompareTo(maxValueInclusive) > 0) { throw new ArgumentException("minimum value must not be greater than maximum value"); } return (value.CompareTo(minValueInclusive) >= 0 && value.CompareTo(maxValueInclusive) <= 0); } The Between function takes any object which supports IComparable<T> and performs syntactic sugar comparison with the inclusive min and max values. What's more, it adds a basic sanity check for the comparison. How many times do I do that sanity check in my normal code (!)? Now the conditional is if (summerCatalog.Products[0].ProductCategories[0].ParentCategoryID.Between(1, 4)) { ///... } At least I don't have to refactor this in my brain while reading. Sure, you might say, but you could have just de-referenced the deep value and then have a shorter conditional, like so: Category category = summerCatalog.Products[0].ProductCategories[0]; if (category.ParentCategoryID >= 1 && category.ParentCategoryID <= 4) { //... }Yes - of course - but it adds a line of code, places the burden of reading the very common idiom ( x >= a && x <= b) on me, and I constantly stumble on the lest-than-or-equal vs. less-than and it doesn't check for my boundaries being inadvertently swapped. So there you have it. A simple extension cuts down your lines of code, makes long text shorter and saves lives. Which begs the question: is this already part of the language - and should it be?