{"id":14,"date":"2008-02-19T19:06:58","date_gmt":"2008-02-20T00:06:58","guid":{"rendered":"http:\/\/www.peteonsoftware.com\/?p=14"},"modified":"2024-03-02T17:05:52","modified_gmt":"2024-03-02T22:05:52","slug":"c-extension-methods","status":"publish","type":"post","link":"https:\/\/www.peteonsoftware.com\/index.php\/2008\/02\/19\/c-extension-methods\/","title":{"rendered":"C# Extension Methods"},"content":{"rendered":"<p>One of my favorite features of C# 3.0 is the extension method.  An extension method basically allows you to add a method to a class without altering the class itself.  All you need to do is declare some static methods with a &#8220;this&#8221; keyword in the parameters.  .Net will then add this method on to whatever class you indicate is a parameter of the method (immediately following the &#8220;this&#8221; keyword).  Then, as long as you have included the namespace in your using declarations in the code file, you are all set.  Some examples would probably help.  Here are some sample declarations. <\/p>\n<pre>\r\npublic static class MyExtensions\r\n{\r\n    \/\/\/ &lt;summary&gt;\r\n    \/\/\/ Validates (poorly) if an email address is in\r\n    \/\/\/ the right format.\r\n    \/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;param name=\"address\"&gt;The email address to validate&lt;\/param&gt;\r\n    \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n    public static bool IsEmailAddress(this string address)\r\n    {\r\n        \/\/ Note: A purposely short pattern.  Not suitable\r\n        \/\/ for enterprise-level validation\r\n        Regex regex = new Regex(@\"^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$\");\r\n        return regex.IsMatch(address);\r\n    } \r\n\r\n    \/\/\/ &lt;summary&gt;\r\n    \/\/\/ Determines the future datetime, given the number\r\n    \/\/\/ of minutes to go forward.\r\n    \/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;param name=\"minutes\"&gt;Number of Minutes to Add&lt;\/param&gt;\r\n    \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n    public static DateTime MinutesFromNow(this int minutes)\r\n    {\r\n        return System.DateTime.Now.AddMinutes(minutes);\r\n    } \r\n\r\n    \/\/\/ &lt;summary&gt;\r\n    \/\/\/ Reverses the characters in a string. \r\n    \/\/\/ This method should have been included in the base library.\r\n    \/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;param name=\"input\"&gt;The string to be reversed&lt;\/param&gt;\r\n    \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n    public static string Reverse(this string input)\r\n    {\r\n        char[] inputArray = input.ToCharArray();\r\n        Array.Reverse(inputArray);\r\n        return new string(inputArray);\r\n    }\r\n}\r\n<\/pre>\n<p>You can see that I&#8217;ve created three methods and added XML comments to them (so I get intellisense on those methods later).  Looking at the Reverse method, I declare it just like a normal method, &#8220;public static string Reverse&#8221; but then in the arguments, I just add a &#8220;this&#8221; before I set the parameter.  So, instead of just &#8220;string input&#8221;, I have &#8220;this string input&#8221;.  This tells .Net to add this method as an extension on the string class.  <\/p>\n<p>You can see from this example that I see my Reverse method in a string&#8217;s intellisense as well as my comments for the method.<br \/>\n<img decoding=\"async\" src=\"https:\/\/www.peteonsoftware.com\/images\/ReverseMethodExample.jpg\" alt=\"Example of the Reverse() extension method\" title=\"Example of the Reverse() extension method\" \/><\/p>\n<p>My total code to use each of my extension methods listed above is as follows.<\/p>\n<pre>\r\nstatic void Main()\r\n{\r\n    Console.WriteLine(\"Reversed String: {0}\", \"PeteOnSoftwareRules!\".Reverse());\r\n    Console.WriteLine(\"Now: {0}\", System.DateTime.Now);\r\n    Console.WriteLine(\"In 20 Mins: {0}\", 20.MinutesFromNow());\r\n    Console.WriteLine(\"president@whitehouse.gov: {0}\", \"president@whitehouse.gov\".IsEmailAddress());\r\n    Console.WriteLine(\"NotAnEmailAddress: {0}\", \"NotAnEmailAddress\".IsEmailAddress());\r\n}\r\n<\/pre>\n<p>When I run the code, I get the following results.<br \/>\n<img decoding=\"async\" src=\"https:\/\/www.peteonsoftware.com\/images\/ExtensionResults.jpg\" alt=\"Example of the extension methods' output.\" title=\"Example of the extension methods' output.\" \/><\/p>\n<p>Good so far, but for now it seems like I am just changing how you would write some validation methods.  Instead of IsEmailAddress(&#8220;a@b.com&#8221;), I am suggesting you write &#8220;a@b.com&#8221;.IsEmailAddress().  That is true so far.  You could also create your own type that inherits from string and add a method, but then everyone else would have to use your type instead of the built-in .Net type.  That&#8217;s not good at all.  Additionally, extension methods add value by solving another problem.<\/p>\n<p>Sometimes, you have to work with a framework or some third party class that has been sealed.  I have for you the following example.  It isn&#8217;t super useful, but concise, and will show my point \ud83d\ude09<\/p>\n<pre>\r\npublic sealed class CannotInheritAndExtend\r\n{\r\n    public string FirstName = string.Empty;\r\n    public string LastName = string.Empty; \r\n\r\n    public void PrintFirstName()\r\n    {\r\n        Console.WriteLine(\"First Name: {0}\", this.FirstName);\r\n    }\r\n}\r\n<\/pre>\n<p>I really need this class to write out the last name, also.  With this example, it is impossible to say &#8220;public class WillInheritAndExtend : CannotInheritAndExtend&#8221; and then just add my own method.  Go ahead and try.  You will get a beautiful compiler error.  What you can do, however, is the following:<\/p>\n<pre>\r\npublic static void PrintLastName(this CannotInheritAndExtend input)\r\n {\r\n    Console.WriteLine(\"Last Name: {0}\", input.LastName);\r\n }\r\n<\/pre>\n<p>Now my method is included in intellisense for the original class.<br \/>\n<img decoding=\"async\" src=\"https:\/\/www.peteonsoftware.com\/images\/ExtendSealedClass.jpg\" alt=\"Intellisense for the new method on the sealed class.\" title=\"Intellisense for the new method on the sealed class.\" \/><\/p>\n<p>So, now I can have this code<\/p>\n<pre>\r\nCannotInheritAndExtend a = new CannotInheritAndExtend();\r\na.FirstName = \"pete\";\r\na.LastName = \"shearer\";\r\na.PrintFirstName();\r\na.PrintLastName();\r\n<\/pre>\n<p>that produces the desired output.<br \/>\n<img decoding=\"async\" src=\"https:\/\/www.peteonsoftware.com\/images\/ExtendSealedClassResults.jpg\" alt=\"Results of new method on the sealed class.\" title=\"Results of new method on the sealed class.\" \/><\/p>\n<p>As you can see, extension methods are really very helpful.  They allow you to keep original types intact, but extend functionality onto them.  I hope you find them as useful and cool as I do.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of my favorite features of C# 3.0 is the extension method. An extension method basically allows you to add a method to a class without altering the class itself. All you need to do &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[15],"tags":[89,19],"class_list":["post-14","post","type-post","status-publish","format-standard","hentry","category-code-tips","tag-code-tips","tag-extension-methods"],"_links":{"self":[{"href":"https:\/\/www.peteonsoftware.com\/index.php\/wp-json\/wp\/v2\/posts\/14","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.peteonsoftware.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.peteonsoftware.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.peteonsoftware.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.peteonsoftware.com\/index.php\/wp-json\/wp\/v2\/comments?post=14"}],"version-history":[{"count":0,"href":"https:\/\/www.peteonsoftware.com\/index.php\/wp-json\/wp\/v2\/posts\/14\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.peteonsoftware.com\/index.php\/wp-json\/wp\/v2\/media?parent=14"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.peteonsoftware.com\/index.php\/wp-json\/wp\/v2\/categories?post=14"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.peteonsoftware.com\/index.php\/wp-json\/wp\/v2\/tags?post=14"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}