Extension methods in C#
Extension methods enable you to add your own methods to already existing system types without deriving from those types. Extension methods are always static but they are called as a instance methods on the extended types. We can extend types like string, double, DateTime etc. as well as LINQ queries which already are extensions of IEnumerable type.
Extended types can be used as a helper methods that you can compile and use in all your projects.
Lets start with the simple string extensions. First example simply checks if string has a value. The second one strips html tags from the string.
/// <summary> /// Determines whether this instance of string is not null or empty. /// </summary> public static bool HasValue(this string text) { return !string.IsNullOrEmpty(text); } /// <summary> /// Strips html tags from the string /// </summary> public static string HtmlStrip(this string input) { input = Regex.Replace(input, "<style>(.|\n)*?</style>", string.Empty); input = Regex.Replace(input, @"<xml>(.|\n)*?</xml>", string.Empty); return Regex.Replace(input, @"<(.|\n)*?>", string.Empty); }
Similar is with the double extensions
/// <summary> /// Rounds the value to last 10s /// </summary> public static double RoundOff(this double i) { return ((double)Math.Round(i / 10.0)) * 10; }
The sample below is very useful when displaying dates. It displays friendly string with the time left to an event, it extends DateTime type.
public static string ToDateLeftString(this DateTime input) { var oSpan = DateTime.Now.Subtract(input); var TotalMinutes = oSpan.TotalMinutes; var Suffix = " ago"; if (TotalMinutes < 0.0) { TotalMinutes = Math.Abs(TotalMinutes); Suffix = " from now"; } var aValue = new SortedList<double, Func<string>>(); 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; }
The last example extends the IEnumerable type so we are actually adding a new LINQ function.
/// <summary> /// Selects the item with maximum of the specified value. /// </summary> public static T WithMax<T, TKey>(this IEnumerable<T> list, Func<T, TKey> keySelector) { return list.OrderByDescending(i => keySelector(i)).FirstOrDefault(); }
When testing above methods you will get following results
static void Main(string[] args) { //DateTime extended method var myDate = DateTime.Now.AddDays(7); var dateLeft = myDate.ToDateLeftString(); //result: "6 days from now" //System.String extended method var myNoHtmlString = "<br><b>test</b>".HtmlStrip(); //result: "test" //or var hasStringValue = "test string".HasValue(); //result: true //System.Double extension double myTo10sRoundedValue = (66.3).RoundOff(); //result: 70 //Linq extensions List<int> list = new List<int>() { 1, 2, 3 }; var max = list.WithMax(i => i); //result: 3 }
I have included sample project below so you can do some testing yourself.
ExtensionMethods