,
Extension methods were added in C# 3.0 and are a great way to add commonly used functionality to your projects in an object oriented way that cuts down on repetitive code. While extension methods are an underlying feature of C#, I am going to focus on their use in a view in an ASP.NET MVC project. The same principles apply to using them in any C# code..
I write a lot of ecommerce-related web applications, so I am constantly having to output prices formatted as currency. While I could just use the String.format method directly in a view, I prefer something a little more elegant and less repetitive. By adding a ToCurrency method to the decimal type, I can easily output a formatted string.
Start by adding a new class to your project with its own namespace, for example myproject.Extensions:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace myProject.Extensions {
Add a static class – this class will have methods added to it that will become your extension methods:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace myProject.Extensions { public static class Extensions { } }
Each static method you add to the class will become an extension method. You tie it to a particular type by using the this keyword and a parameter of the type you want to extend:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace myProject.Extensions { public static class Extensions { public static string ToCurrency(this decimal amount) { return String.Format("{0:C}", amount); } } }
The ToCurrency method will be added to the decimal type because it is specified as the parameter type and includes the keyword this. I am simply passing the parameter to the String.Format method and returning a formatted string.
Calling the extension method either in other code such as a controller or within a view is simple. You just need to be certain to include the namespace in your class or view with a using statement. This is an example of it in a Razor view:
@model myProject.Models.Product @using myProject.Extensions; <span>@Model.Price.ToCurrency()</span>
The price property of the Product class is a decimal, so the method is available as if it were part of the underlying type.
You can add extension methods to any class the same way. Another example is providing a formatted address for an address object:
public static string GetFormatted(this Address address) { string a=address.Name+"<br>"; if(address.Company!=null) { a+=address.Company+"<br>"; } a+=address.Address1+"<br>"; if(address.Address2!=null) { a+=address.Address2+"<br>"; } a+=address.City+", "+address.State+" "+address.Zip return a; }
Then, within a view, you can easily output a formatted address without having to put all the logic into the view:
@Model myProject.Models.Order @using myProject.Extensions <div> @Model.BillingAddress.GetFormatted() </div>
Since the BillingAddress property of the Order object is of type Address, the extension method is available as if it were a native part of the class. While you could add the method directly to the underlying class, if you are working with Entity Framework or a class you may not have the source code to, you can extend it without having to modify the original class.
While you could just as easily create a library of functions to call, extension methods provide a more elegant solution to code reuse and providing utility functions. The can even be put into a separate class library project to reuse them between projects.
For more information about Extension methods, see:
http://weblogs.asp.net/dwahlin/archive/2008/01/25/c-3-0-features-extension-methods.aspx
http://csharp.net-tutorials.com/csharp-3.0/extension-methods/
If you have extension methods that /should/ be working in your view, but aren’t, hunt for misspelled property names within the view. In some scenarios, if you fat-finger one of your model’s property names in the Razor view, Visual Studio will happily let you—no red squiggly, no compile error. It will just turn the reference into a Dynamic instead of a strongly typed Model instance. When this happens, your properties are no longer strongly-typed strings, DateTimes, etc.; they all become plain objects. When that happens, your extension methods come unglued (unless, of course, they extend System.Object).
Can cast the dynamic objects back to their original strongly typed values like
((decimal)MyAmount).ToCurrency()