Extension method is one of the useful feature of .NET.
In OOP programming, we respect objects accessibility levels. We know which type we can access, which type we can extend by examining its access modifiers. For example, a type marked with
sealed cannot be overridden. Most of the built in type in .NET is sealed and cannot be overridden. Or if you buy a third party component, it is obvious that certain types cannot be overridden. But in some cases it becomes essential to extend built in types functionality to make the coding easier or in sometimes for business meet.
So for the aforementioned situation, .NET has introduced a new way of extending the built in types or any types that you cannot extend ( in fact for all types), and the way is
extension method.
As the name implies, Extension methods allow you to easily extend a type through method additon, add a new method, for example, an
integer or
string or datetime , without re-compiling or modifying the types definition. The implementation will reside in you place, and you can easily be able to use that to you application.
In our daily need, when we work with TextBox or DropDownList, these controls holds data as string. But in some cases, we may need to convert this string value to int type or datetime. To do this we normally do some conversion like this
int quantity = int.Parse(txtAmount.Text);
or
int quantity = Convert.ToInt32(txtAmount.Text);
In above code, error is not properly handled an involves some extra coding effort to convert. Rather if there was a method with string type that would convert to int type, that would be easier to use.
The Extension Method has this power to add new methods with built in types.
How To Implement Extension Method:
In order to implement the Extension Method, the following steps needs to be followed:
1. Define the method in a static class .
2. Define you method marked as static method.
3. Pass the first argument as type parameter with the keyword this preceded.
4. Pass additional parameter if you need.
5. Implement your functionality..
That's it.
No go for the implementation in hand. Here is some common extension methods that we need in our daily programming.
Extension Method for String type:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ExtensionMethodsLibrary
{
public static class StringExtensions
{
/// <summary>
/// Converts a string to Int32. If not convertible, returns null.
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static Int32? ToInt32OrNull(this string str)
{
Int32 value;
bool isParsed = Int32.TryParse(str, out value);
if (isParsed)
return value;
else
return null;
}
/// <summary>
/// Converts a string to double. If not convertible, returns null.
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static double? ToDoubleOrNull(this string str)
{
double value;
bool isParsed = double.TryParse(str, out value);
if (isParsed)
return value;
else
return null;
}
/// <summary>
/// Converts a string to Int64. If not convertible, returns null.
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static Int64? ToInt64OrNull(this string str)
{
Int64 value;
bool isParsed = Int64.TryParse(str, out value);
if (isParsed)
return value;
else
return null;
}
/// <summary>
/// An extension method for string to get the int value.
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static Int32 ToInt32(this string str)
{
Int32 value;
bool isParsed = Int32.TryParse(str, out value);
if (isParsed)
return value;
else
throw new Exception("Data type mitchmatch. The string is not a valid integer value.");
}
/// <summary>
/// An extension method for string to get the long value.
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static Int64 ToInt64(this string str)
{
Int64 value;
bool isParsed = Int64.TryParse(str, out value);
if (isParsed)
return value;
else
throw new Exception("Data type mitchmatch. The string is not a valid Int64 value.");
}
/// <summary>
/// An extension method for string to get the double value.
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static double ToDouble(this string str)
{
double value;
bool isParsed = double.TryParse(str, out value);
if (isParsed)
return value;
else
throw new Exception("Data type mitchmatch. The string is not a valid double value.");
}
/// <summary>
/// An extension method for string to get the Int16 value.
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static Int16 ToInt16(this string str)
{
Int16 value;
bool isParsed = Int16.TryParse(str, out value);
if (isParsed)
return value;
else
throw new Exception("Data type mitchmatch. The string is not a valid Int16 value.");
}
/// <summary>
/// Converts a string to datetime, if not convertible, null value is returned.
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static DateTime? ToDateTimeOrNull(this string str)
{
DateTime value;
bool isParsed = DateTime.TryParse(str, out value);
if (isParsed)
return value;
else
return null;
}
/// <summary>
/// Converts a string to datetime, if not convertible,exception is thrown.
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static DateTime ToDateTime(this string str)
{
DateTime value;
bool isParsed = DateTime.TryParse(str, out value);
if (isParsed)
return value;
else
throw new Exception("Data is not in correct format.");
}
}
}
Extension methods for Datetime type:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ExtensionMethodsLibrary
{
public static class DateTimeExtensions
{
public static string ToStringOrEmptyIfDefault(this DateTime dt)
{
string value = dt == default(DateTime) ? "" : dt.ToString();
return value;
}
public static string ToStringOrEmptyIfDefault(this DateTime dt, string format)
{
if (dt != default(DateTime))
{
return dt.ToString(format);
}
else
return string.Empty;
}
public static string ToStringOrEmptyIfDefault(this DateTime? dt, string format)
{
if (dt.HasValue && dt.Value != default(DateTime))
{
DateTime date = (DateTime)dt;
return date.ToString(format);
}
else
return string.Empty;
}
public static string ToStringOrEmptyIfDefault(this DateTime? dt)
{
string value = dt == default(DateTime) ? "" : dt.ToString();
return value;
}
}
}
Extension Method for DataRow type:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ExtensionMethodsLibrary
{
public static class DBAccessExtension
{
/// <summary>
/// Gets the value from data reader with columnname or default value if the value is null.
/// </summary>
/// <typeparam name="T"> Type of value to return</typeparam>
/// <param name="reader"></param>
/// <param name="columnName"></param>
/// <returns></returns>
public static T GetValueOrDefault<T>(this IDataReader reader, string columnName)
{
object columnValue = reader[columnName];
T returnValue = default(T);
if (!(columnValue is DBNull))
{
returnValue = (T)Convert.ChangeType(columnValue, typeof(T));
}
return returnValue;
}
/// <summary>
/// Converts a datarow column value to Int32 value, if the column is null, then the value is the default value for int.
/// </summary>
/// <param name="dataRow"></param>
/// <param name="columnName"></param>
/// <returns></returns>
public static int ToInt32(this DataRow dataRow, string columnName)
{
object columnValue = dataRow[columnName];
int returnValue = default(int);
if (!(columnValue is DBNull))
{
returnValue = (int)Convert.ChangeType(columnValue, typeof(int));
}
return returnValue;
}
/// <summary>
/// Converts a datarow column value to GUID value, if the column is null, then the value is the default value for GUID.
/// </summary>
/// <param name="dataRow"></param>
/// <param name="columnName"></param>
/// <returns></returns>
public static Guid ToGuid(this DataRow dataRow, string columnName)
{
object columnValue = dataRow[columnName];
Guid returnValue = default(Guid);
if (!(columnValue is DBNull))
{
returnValue = (Guid)Convert.ChangeType(columnValue, typeof(Guid));
}
return returnValue;
}
/// <summary>
/// Converts a datarow column value to double value, if the column is null, then the value is the default value for double.
/// </summary>
/// <param name="dataRow"></param>
/// <param name="columnName"></param>
/// <returns></returns>
public static double ToDouble(this DataRow dataRow, string columnName)
{
object columnValue = dataRow[columnName];
double returnValue = default(double);
if (!(columnValue is DBNull))
{
returnValue = (double)Convert.ChangeType(columnValue, typeof(double));
}
return returnValue;
}
/// <summary>
/// Converts a datarow column value to DateTime value, if the column is null, then the value is the default value for DateTime.
/// </summary>
/// <param name="dataRow"></param>
/// <param name="columnName"></param>
/// <returns></returns>
public static DateTime ToDateTime(this DataRow dataRow, string columnName)
{
object columnValue = dataRow[columnName];
DateTime returnValue = default(DateTime);
if (!(columnValue is DBNull))
{
returnValue = (DateTime)Convert.ChangeType(columnValue, typeof(DateTime));
}
return returnValue;
}
/// <summary>
/// Converts a datarow column value to bool value, if the column is null, then the value is the default value for bool.
/// </summary>
/// <param name="dataRow"></param>
/// <param name="columnName"></param>
/// <returns></returns>
public static bool ToBoolean(this DataRow dataRow, string columnName)
{
object columnValue = dataRow[columnName];
bool returnValue = default(bool);
if (!(columnValue is DBNull))
{
returnValue = (bool)Convert.ChangeType(columnValue, typeof(bool));
}
return returnValue;
}
/// <summary>
/// Converts a datarow column value to string value, if the column is null, then the value is the default value for string.
/// </summary>
/// <param name="dataRow"></param>
/// <param name="columnName"></param>
/// <returns></returns>
public static string ToString(this DataRow dataRow, string columnName)
{
object columnValue = dataRow[columnName];
string returnValue = default(string);
if (!(columnValue is DBNull))
{
returnValue = (string)Convert.ChangeType(columnValue, typeof(string));
}
return returnValue;
}
}
}
How To Use Extension Methods:
If your class where you implemented extension methods has namespace different than you are using, import that namespace in your class.
For previous example, the class is defined in a namespace "ExtensionMethodsLibrary". So to use that you have to import that in your code.
Here is how you can use this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ExtensionMethodsLibrary;
namespace ExtensionMethods.Controllers
{
public class HomeController : Controller
{
public void CallExtensionMethods()
{
string str_IntVal = "100";
string str_DateVal = "1/1/2012";
string str_DblVale = "100.00";
//Convert to Int from string using extension methods.
Int32 intVal = str_IntVal.ToInt32();
Int64 int64Val = str_IntVal.ToInt64();
double dblValue = str_DblVale.ToDouble();
DateTime dtValue = str_DateVal.ToDateTime();
//Nullable types conversion.
Int32? NblintVal = str_IntVal.ToInt32OrNull();
Int64? Nblint64Val = str_IntVal.ToInt64OrNull();
double? NbldblValue = str_DblVale.ToDoubleOrNull();
DateTime? NbldtValue = str_DateVal.ToDateTimeOrNull();
//Null or not convertible values.
DateTime? dt = "".ToDateTimeOrNull();
int? nullInt = "".ToInt32OrNull();
}
}
}
Caution:
If you do implement extension methods for a given type, remember the following two points:
-
An extension method will never be called if it has the same signature as a method defined in the type.
-
Extension methods are brought into scope at the namespace level.
For example, if you have multiple static classes that contain extension
methods in a single namespace named Extensions, they will all be brought into scope by the using Extensions; directive.