Alright folks, this is my arsenal of useful Extension Methods for .NET 3.0+ mostly written by me to help with development productivity.
Some real time-savers in here such as .ToInt() and .ToDateTime() (with and without a default fallback value), plus a simple RegEx matcher thrown into the mix and my CloneProperties method I wrote yesterday.
Included namespaces are:
- StringExtensions;
- NullableBooleanExtensions;
- ObjectExtensions;
- ValidatorExtensions and;
- Updated 18-Feb-2009: HtmlHelperExtensions! (How could I forget these guys)
I mean you can go on forever with every possible combination, but these are the few I’ve found need for the most.
Once you’ve included the code below, a simple namespace reference is all you need and away you go.

namespace Application.Business.Utility
{
public static class StringExtension
{
///
/// Convert to Integer specifying a default value.
///
///
///
///
public static int ToInt(this string str, int defaultValue)
{
int res;
if (!string.IsNullOrEmpty(str))
return int.TryParse(str, out res) ? res : defaultValue;
else
return defaultValue;
}
///
/// Convert to Integer.
///
///
///
public static int ToInt(this string str)
{
int res;
try
{
if (!string.IsNullOrEmpty(str))
res = int.Parse(str);
else
res = 0;
}
catch (OverflowException)
{
throw;
}
catch (Exception)
{
res = 0;
}
return res;
}
///
/// Convert to Long specifying a default value.
///
///
///
///
public static long ToLng(this string str, long defaultValue)
{
long res;
try
{
if (!string.IsNullOrEmpty(str))
res = long.Parse(str);
else
res = defaultValue;
}
catch (OverflowException)
{
throw;
}
catch (Exception)
{
res = defaultValue;
}
return res;
}
///
/// Convert to Long.
///
///
///
public static long ToLng(this string str)
{
long res;
if (!string.IsNullOrEmpty(str))
return long.TryParse(str, out res) ? res : 0;
else
return 0;
}
///
/// Convert to Decimal specifying a default value.
///
///
///
///
public static decimal ToDec(this string str, decimal defaultValue)
{
decimal res;
if (!string.IsNullOrEmpty(str))
return decimal.TryParse(str, out res) ? res : defaultValue;
else
return defaultValue;
}
///
/// Convert to Decimal.
///
///
///
public static decimal ToDec(this string str)
{
decimal res;
if (!string.IsNullOrEmpty(str))
return decimal.TryParse(str, out res) ? res : 0;
else
return 0;
}
///
/// Convert to Boolean specifying a default value.
///
///
///
///
public static bool ToBool(this string str, bool defaultValue)
{
bool res;
if (!string.IsNullOrEmpty(str))
return bool.TryParse(str, out res) ? res : defaultValue;
else
return false;
}
///
/// Convert to Boolean.
///
///
///
public static bool ToBool(this string str)
{
bool res;
if (!string.IsNullOrEmpty(str))
return bool.TryParse(str, out res) ? res : false;
else
return false;
}
///
/// Convert to DateTime specifying a default value.
///
///
///
///
public static DateTime ToDateTime(this string str, DateTime defaultValue)
{
DateTime res;
if (!string.IsNullOrEmpty(str))
return DateTime.TryParse(str, out res) ? res : defaultValue;
else
return DateTime.MinValue;
}
///
/// Convert to DateTime.
///
///
///
public static DateTime ToDateTime(this string str)
{
DateTime res;
if (!string.IsNullOrEmpty(str))
return DateTime.TryParse(str, out res) ? res : DateTime.MinValue;
else
return DateTime.MinValue;
}
///
/// Indicates whether the regular expression finds a match in the input string using the regular expression specified in the pattern parameter.
///
///
String to match
///
Regular expression, eg. [a-Z]{3}
///
Return true only if string was matched entirely
///
public static bool IsMatch(this string value, string regularExpression, bool matchEntirely)
{
return Regex.IsMatch(value, matchEntirely ? "\\A" + regularExpression + "\\z" : regularExpression);
}
}
public static class NullableBooleanExtension
{
///
/// Convert to Integer specifying a default value.
///
///
///
///
public static int ToInt(this bool? value, int defaultValue)
{
int res;
try
{
res = value.HasValue ? Convert.ToInt32(value) : defaultValue;
}
catch (Exception)
{
res = defaultValue;
}
return res;
}
///
/// Convert to Integer.
///
///
///
public static int ToInt(this bool? value)
{
int res;
try
{
res = value.HasValue ? Convert.ToInt32(value) : 0;
}
catch (Exception)
{
res = 0;
}
return res;
}
}
public static class ObjectExtension
{
///
/// Clone properties from an original object to a destination object.
///
///
///
///
///
public static void CloneProperties(this T1 origin, T2 destination)
{
// Instantiate if necessary
if (destination == null) throw new ArgumentNullException("destination", "Destination object must first be instantiated.");
// Loop through each property in the destination
foreach (var destinationProperty in destination.GetType().GetProperties())
{
// find and set val if we can find a matching property name and matching type in the origin with the origin's value
if (origin != null && destinationProperty.CanWrite)
{
origin.GetType().GetProperties().Where(x => x.CanRead && (x.Name == destinationProperty.Name && x.PropertyType == destinationProperty.PropertyType))
.ToList()
.ForEach(x => destinationProperty.SetValue(destination, x.GetValue(origin, null), null));
}
}
}
}
public static class ValidatorExtension
{
///
/// Return true if value is between a range of values.
///
///
public static bool Between(this int value, int start, int end, bool inclusive)
{
if (inclusive)
return (value >= start && value <= end) ? true : false;
return (value > start && value < end) ? true : false;
}
}
public static class HtmlHelperExtensions
{
#region HtmlHelper extensions
///
/// Format date/time object into html representation of 'relative time' format, eg. "5 seconds ago".
///
///
///
///
public static string FormatDateTimeRelative(this HtmlHelper htmlHelper, DateTime? value)
{
if (value.HasValue)
{
// As suggested on stackoverflow.com and found to be the most comprehensive method.
// http://stackoverflow.com/questions/11/how-do-i-calculate-relative-time
TimeSpan oSpan = DateTime.Now.Subtract(value.Value);
double TotalMinutes = oSpan.TotalMinutes;
string Suffix = " ago";
if (TotalMinutes < 0.0)
{
TotalMinutes = Math.Abs(TotalMinutes);
Suffix = " from now";
}
Dictionary> aValue = new Dictionary>();
aValue.Add(0.75, () => "less than a minute");
aValue.Add(1.5, () => "about a minute");
aValue.Add(45, () => string.Format("{0} minutes", Math.Round(TotalMinutes)));
aValue.Add(90, () => "about an hour");
aValue.Add(1440, () => string.Format("about {0} hours", Math.Round(Math.Abs(oSpan.TotalHours)))); // 60 * 24
aValue.Add(2880, () => "a day"); // 60 * 48
aValue.Add(43200, () => string.Format("{0} days", Math.Floor(Math.Abs(oSpan.TotalDays)))); // 60 * 24 * 30
aValue.Add(86400, () => "about a month"); // 60 * 24 * 60
aValue.Add(525600, () => string.Format("{0} months", Math.Floor(Math.Abs(oSpan.TotalDays / 30)))); // 60 * 24 * 365
aValue.Add(1051200, () => "about a year"); // 60 * 24 * 365 * 2
aValue.Add(double.MaxValue, () => string.Format("{0} years", Math.Floor(Math.Abs(oSpan.TotalDays / 365))));
return aValue.First(n => TotalMinutes < n.Key).Value.Invoke() + Suffix;
}
return string.Empty;
}
///
/// Truncate text by given input to 40 characters with trailing ellipsis.
///
///
///
///
public static string Truncate(this HtmlHelper htmlHelper, string text)
{
if (!string.IsNullOrEmpty(text))
return text.Length > 40 ? text.Substring(0, 40) + "…" : text;
return string.Empty;
}
#endregion
}
}
17 Comments
No FormatWith?
ExtensionOverflow has a more comphrensive lib of extension methods.
I am curious to see what others say on the usefulness of the conversion extension methods and how dangerous they may be to other developers.
On the ValidatorExtension, you could change it to be an IComparableExtension where instead of extending an int you extend IComparable to take something like this (apologies for the formatting here):
public static bool IsBetween( this T inputValue, T minValue, T maxValue ) where T : IComparable
{
return inputValue.CompareTo( minValue ) >= 0 &&
inputValue.CompareTo( maxValue ) <= 0;
}
On my last post the IsBetween method did take a generic type parameter, but it did not make it on the final comment.
So, when ToInt() causes an OutOfMemoryException or a ExecutionEngineException or whatnot, it results to 0. Probably, especially for general purpose methods, you should use more specific catch-blocks.
Great article.
I find the combination of extension methods and generics to be both elegant and timesaving:
public static Nullable ToNullable(this object o)
where T : struct
{
return (o != null && o != DBNull.Value) ? (Nullable)o : null;
}
public static T ToDefaultable(this object o)
where T : struct
{
return (o != null && o != DBNull.Value) ? (T)o : default(T);
}
What do you think?
My generic parameters got lost. Let me try again…
public static Nullable<T> ToNullable<T>(this object o)
where T : struct
{
return (o != null && o != DBNull.Value) ? (Nullable<T>)o : null;
}
public static T ToDefaultable<T>(this object o)
where T : struct
{
return (o != null && o != DBNull.Value) ? (T)o : default(T);
}
I’ve been there myself as well. Just discovered extension methods, and creating a .ToInt() on string, or perhaps even on object itself would be a major productivity gain.
However, I really dislike it. String should not have a ToInt() method as it’s only a very small subset of all strings that can actually be converted to ints, and intellisense won’t help you notice the difference – only your application code will. Having a ToInt (my ramblings concern all of the methods, not just ToInt) will nurture you into writing bad code, not thinking enough about where to convert what.
I’d much rather write Convert.ToInt32() the relatively few places I do a convert. For the QueryString (or Form – can’t see which you’re referring), I’ve got a generic QueryStringHelper object that’ll do the conversions for me:
QueryStringHelper.To(“moduleid”);
That makes conversions easier on the eye (imho) and contains the logic where it belongs – away from the string object.
Not sure I see the benefit of calling a method ToLng. Why not ToLong, since that’s what it is doing. Oh, right, you would have to type that extra character…
@redsquare: Wow, cool redsquare. Thanks for sharing the link. Hadn’t seen this.
@Rob Packwood: Nice, looks like a great generic implementation for IsBetween().
@Chris: Perhaps. This was merely a collection of methods I’ve found useful over time and haven’t really looked back on them too much – I’ve never encountered these exceptions so I guess never thought on how they could be improved!
@Robert Hanlon: That’s kinda cool Rob, so it will convert anything to a Nullable type?
@Mark Rasmussen: Yes I see where you’re coming from Mark, but I don’t think there is a reason to dislike it. When I say that, it is from my perspective and my disciplines, I would use it intentionally as a “convenience” to Convert.ToInt32() and it should be no less thought out than if you were to use the original convert method. I’ve been working with a lot of legacy systems of late, cutting up files and such, so I have found the ToInt() method personally incredibly useful with what I needed to do.
I completely forgot about my HtmlHelperExtensions which were stored in another file! I have just updated my samples.
@Steve: You bet. That would be horrible. No really because I am a consistency freak and I think I just wanted them all three characters. But then I ruined it with ToBool & ToDateTime anyway….
Graham, no, my ToNullable method converts things cast as object to the Nullable<> form of some value type (int, double, bool, and DateTime get the most mileage). The compiler checks that these are value types with the “where T : struct” constraint. Reference types, including string, don’t need ToNullable, because those variables can already be set to null.
It’s most effective when reading from the database:
int? imageKey = row["imagekey"].ToNullable();
(…where “row” is a DataRow, natch.)
It essentially replaces this code:
int? imageKey;
if (row["imagekey"] == null) imageKey = null;
else imageKey = (int)row["imageKey"];
It doesn’t solve any groundbreaking problems, but it does clean code up, which is what I find extension methods are best at.
@Robert: Sorry, I said anything because I saw the object type input, but the “where T : struct” constraint I understand, nice, as all value types derive from a struct and as you say ref types do not need to be changed. Very cool.
Did I miss something? Where are the downloads? I don’t see how I can get your code?! :-/ Please help.
Why, in ToInt(defaultValue), does a null or empty string convert to 0 instead of defaultValue?
@Peter: the code should have loaded on the page in source code formatting? Do you see the scrollable div?
@James: It shouldn’t. This has been fixed. Cheers dude.
3 Trackbacks/Pingbacks
15 Helpful .NET Extension Methods to Increase Productivity « {Programming} & Life…
Thank you for submitting this cool story – Trackback from DotNetShoutout…
[...] 15 Helpful .NET Extension Methods to Increase Productivity « {Programming} & Life. Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages. [...]
[...] (Dan Fernandez and Brian Keller), I really appreciate the video review regarding my post “15 Helpful .NET Extension Methods to Increase Productivity” and the plug to my website! The extension methods were nothing [...]
Post a Comment