This article assumes that user has knowledge of C#
programming and the intention of the article is not to stress too much on
extension methods. But, to give an idea on what are extension methods, benefits
and the most important part of the article is not to reinvent the wheel by coding
the methods which are already developed and shared by other developers and
contributed for the benefit of the Microsoft development community. CodePlex
provides the source openly for the developers.
The best resource for any of the Microsoft articles is the
MSDN and to know more about extension methods from the Microsoft words please
refer to the URL http://msdn.microsoft.com/en-us/library/bb383977.aspx.
Before extension methods, we used to write our own methods
in the class whenever needed in our projects. There are many built-in functions
provided by the Microsoft .NET framework which can be used by the developers
without having them to rewrite the code for achieving basic functionality like all
primitive date types can be converted into string object using method
ToString() or to check if both the string objects are equal by Equals(0bject
object) and so on.
Before the
invention of extension methods:
Let us see how a normal developer writes code to achieve
functionality without using the extension methods.
Here in this example we look at two ways of coding:
1.
Writing lines of code without modularity i.e.,
just writing lines of code whenever needed by duplicating the efforts when the
same code is to be used in some other module or project in the application.
2.
Converting the common lines of code into a
method which can be re used whenever needed.
Create a Console application project using visual studio
2008 and modify the file Program.CS with the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ExtensionMethods
{
class Program
{
static void Main(string[]
args)
{
string
userName = "John";
string
emptyString = "";
int?
number = 5;
int?
number2 = null;
//Normally
we use the following condition to check if a string
//is not
an empty value
Console.WriteLine("****Writing lines of code as needed on the
fly****");
if
(!string.IsNullOrEmpty(userName))
Console.WriteLine("User Name is not Empty");
else
Console.WriteLine("User Name is Empty");
if
(!string.IsNullOrEmpty(emptyString))
Console.WriteLine("EmptyString is not Empty");
else
Console.WriteLine("EmptyString is Empty");
//Similarly
to check if an integer is null then return default value
//else
convert the integer value to string value.
if
(number == null)
Console.WriteLine("Number is null and so it is empty");
else
Console.WriteLine("Converted string value of number is {0}",
number.ToString());
if
(number2 == null)
Console.WriteLine("number2 is null and so it is empty");
else
Console.WriteLine("Converted string value of number2 is {0}",
number2.ToString());
Console.WriteLine("*************************************************");
Console.WriteLine("****Calling a method to reuse the same
code*******");
//Otherwise,
we write a method that checks if the string is not null or empty
//More
better way to write code
Console.WriteLine("User Name is Not Empty?? {0}",
IsNotNullOrEmpty(userName));
Console.WriteLine("EmptyString is Not Empty?? {0}",
IsNotNullOrEmpty(emptyString));
//Better
way to write code. Convert the lines of code into a method and call it.
Console.WriteLine("String value of number is {1}", number,
ToString(number,"empty"));
Console.WriteLine("String value of number2 is {1}",
number2, ToString(number2, "empty"));
Console.WriteLine("***********************************************");
Console.ReadLine();
}
/// <summary>
/// Method to check if a string is not null or empty.
/// </summary>
/// <param
name="input"></param>
/// <returns></returns>
static bool IsNotNullOrEmpty(string
input)
{
return
!string.IsNullOrEmpty(input);
}
/// <summary>
/// Method to convert an integer value to string if it is not
null
/// otherwise return default value.
/// </summary>
/// <param
name="value"></param>
/// <param
name="defaultvalue"></param>
/// <returns></returns>
static string ToString(int?
value, string defaultvalue)
{
if
(value == null) return
defaultvalue;
return
value.Value.ToString();
}
}
}
Now run the program:
Tip: There are two
beautiful and helpful tools provided by Microsoft for developer community to
beautify the code to make it more clean and maintainable. One is the Code
Analyzer and other one Code Metrics. Always use the Code
Analyzer and Code Metrics tools in the visual studio to fine tune your code so
that your code will be clean and maintainable. You are not compelled to do all
the changes, but you can follow whenever you feel it is good to change. As a
developer, we sometimes ignore the best practices in a hurry to complete the code
with in the dead line. For example, when I run code analysis on the above
project it shows me the following warning:
CA1305 : Microsoft.Globalization : Because the behavior of
'int.ToString()' could vary based on the current user's locale settings,
replace this call in 'Program.ToString(int?, string)' with a call to
'int.ToString(IFormatProvider)'. If the result of
'int.ToString(IFormatProvider)' will be displayed to the user, specify
'CultureInfo.CurrentCulture' as the 'IFormatProvider' parameter. Otherwise, if
the result will be stored and accessed by software, such as when it is
persisted to disk or to a database, specify 'CultureInfo.InvariantCulture'.
Back to topic. Now in my project, I have to check the string
value and show on the UI the value if it is not empty or null otherwise, show
that it is empty. To check that we use the built-in method for string class
IsNullOrEmpty and accordingly we will display the value in the UI. Similarly, I
have a requirement that I check if a integer value is null then show it as “No
records found” in the UI or convert the integer to string and append to your
message like “5 records found”. To do this we check if a integer is null then
return a default value otherwise, convert the integer to string using method
ToString() and append to the string message you would like to show on the UI.
Note: In general
you cannot assign null value to an int variable. Microsoft has introduced
nullable types in the .NET framework to support assigning null to value types. Note
that reference types already supports null values. To learn more about the
Nullable types refer to the MSDN article http://msdn.microsoft.com/en-us/library/1t3y8s4s(v=vs.80).aspx.
Now what? If I have to use the same methods in different
projects, I cannot rewrite the methods in each class and so we need to place
all these methods in one place. For that we need to create a class library and
add a static class and include all these methods in the class. Then reference
these methods by adding reference to the class library project.
Note: In many
projects, we name this static class as “Helper” since it helps all the projects
in providing the helpful methods in achieving the functionality. It is not
necessary that the class be a static class, but the best practices from
Microsoft says that any class that only supports some operations and does not
need to be instantiated, you can make the class as static. You can learn more
about this from the MSDN article http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.80).aspx.
Also note that even if you do not create static class and instantiate every
time to call the methods, when you run the Code Analyzer tool, it suggests you
make the class as static and use the methods without instantiating the class.
See how the tool helps you even you forget something. That is the great thing
about Microsoft which is committed to make developers life easy.
So, our next step is to create a class library project and
add a static class called “Helper.CS” and add these methods in the class. I
name my project as “Common” and modified the name of the file “Class1.CS” to “Helper.cs”.
Here is my new class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Common
{
public static class Helper
{
/// <summary>
/// Method to check if a string is not null or empty.
/// </summary>
/// <param
name="input"></param>
/// <returns></returns>
public static bool
IsNotNullOrEmpty(string input)
{
return
!string.IsNullOrEmpty(input);
}
/// <summary>
/// Method to convert an integer value to string if it is not
null
/// otherwise return default value.
/// </summary>
/// <param
name="value"></param>
/// <param
name="defaultvalue"></param>
/// <returns></returns>
public static string
ToString(int? value, string
defaultvalue)
{
if
(value == null) return
defaultvalue;
return
value.Value.ToString();
}
}
}
Now add the project reference to the Common project from
ExtensionMethods Console application and modify your “Program.cs” to add the
reference and use the Helper class methods.
Here is my changed code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common;
namespace ExtensionMethods
{
class Program
{
static void Main(string[]
args)
{
string
userName = "John";
string
emptyString = "";
int?
number = 5;
int?
number2 = null;
//Normally
we use the following condition to check if a string
//is not
an empty value
Console.WriteLine("****Writing lines of code as needed on the
fly****");
if
(!string.IsNullOrEmpty(userName))
Console.WriteLine("User Name is not Empty");
else
Console.WriteLine("User Name is Empty");
if
(!string.IsNullOrEmpty(emptyString))
Console.WriteLine("EmptyString is not Empty");
else
Console.WriteLine("EmptyString is Empty");
//Similarly
to check if an integer is null then return default value
//else
convert the integer value to string value.
if
(number == null)
Console.WriteLine("Number is null and so it is empty");
else
Console.WriteLine("Converted string value of number is {0}",
number.ToString());
if
(number2 == null)
Console.WriteLine("number2 is null and so it is empty");
else
Console.WriteLine("Converted string value of number2 is {0}",
number2.ToString());
Console.WriteLine("*************************************************");
Console.WriteLine("****Calling a method to reuse the same
code*******");
//Otherwise,
we write a function that checks if the string is not null or empty
//More
better way to write code
Console.WriteLine("User Name is Not Empty?? {0}", Helper.IsNotNullOrEmpty(userName));
Console.WriteLine("EmptyString is Not Empty?? {0}", Helper.IsNotNullOrEmpty(emptyString));
//Better
way to write code. Convert the lines of code into a method and call it.
Console.WriteLine("String value of number is {1}", number,
Helper.ToString(number, "empty"));
Console.WriteLine("String value of number2 is {1}",
number2, Helper.ToString(number2, "empty"));
Console.WriteLine("***********************************************");
Console.ReadLine();
}
}
}
I am done now. Now I have created a separate class library
project and I am able to reference the common methods used by any of the
projects with in the solution with no much efforts. Even, I am following the
best standards of making the class as static and referring to the methods
without instantiating the class thus avoiding the memory issues too. Then why
do I need extension methods? I am happy with the code in my project and it was
deployed in production and it is performing well.
One fine day, another developer who is new to the project or
imagine a developer who is new to C# coding itself have joined in your team. What
he visualizes is that Microsoft’s tool for .NET so called the “Visual Studio
2008” is so developer friendly and whenever he wants to use the built-in
methods provided by the framework, he just have to put “.” after the variable
and it shows all the methods and properties supported. You might have told him
that you did a great job by adding all the common methods in the static class “Helper”
and he can use that whenever he has to write the similar kind of functionality.
But he may miss that part and plans to reinvent the wheel by writing his own
methods in the code. (This happened in one of my projects and believe me, when
that developer left the team it took lot of efforts in changing his code to
avoid the redundancy). So, how easy it would have been when he put “.” after
the variable, the intellisense have shown him the methods that I have placed in
the Helper file for the same purpose? Definitely, it would have made everyone’s
life easy. Most of the projects have these kind of code integration issues.
Here are the reasons why I go for extension methods:
- Extension methods helps to add methods to
existing types without creating a new derived types.
-
If I am using a Third party library file in my
project and I do not have source code available for the library, the best thing
is to extend the existing types and write your own methods without
understanding their code.
-
It makes developer’s life easy to check what are
all the methods supported by the type variable he is using at one place instead
of searching in the project for the similar kind of method.
-
It helps the first time programmers concentrate
on building the solution without much emphasizing on how to write that
functionality in a separate methods explicitly.
-
Main point being I do not want to differentiate
between my own methods and the built-in methods provided by the framework.
-
With extension methods, now you can add
supported methods to values types which could not have been possible without it.
For example, I have a variable of type double and I want to calculate the
percentage of the value or any other functionality and if I check the
operations supported, they are only few as below:
I would like to extend the methods that are
supported by the variable of type Double. You cannot do it in simple way
without using extension methods.
Hi to Extension
methods:
The basic steps needed to write extension methods are as
below:
1.
You have to include the “This” keyword as the first parameter in the extension method
parameter list preceded by the variable type that you are extending.
2.
Make the extension method as static.
That’s it and you are done with the extension methods for
the types used in your project.
Now, I am going to modify the static helper class to make
the methods as extension methods. My Helper class now looks like below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Common
{
public static class Helper
{
/// <summary>
/// Method to check if a string is not null or empty.
/// </summary>
/// <param
name="input"></param>
/// <returns></returns>
public static bool
IsNotNullOrEmpty(this string input)
{
return
!string.IsNullOrEmpty(input);
}
/// <summary>
/// Method to convert an integer value to string if it is not
null
/// otherwise return default value.
/// </summary>
/// <param
name="value"></param>
/// <param
name="defaultvalue"></param>
/// <returns></returns>
public static string
ToString(this
int? value, string
defaultvalue)
{
if
(value == null) return
defaultvalue;
return
value.Value.ToString();
}
}
Now go to Program.cs file and try to check the methods
supported by the types we have used earlier. You find that they support the
methods that are defined in the helper class.
Now modify your code and run the program. You will find that
the output remained the same. But, now you are able to use the methods as if
they are supported by the framework classes itself. That is the beauty of
extension methods.
Now coming to the last section of this article, the main
intention of this article. CodePlex provides you the source code for the
already defined extension methods that are shared by the developers’ community
to help other developers. You can use these methods in your projects without
investing time on reinventing the wheel. If you have ever developed any other
methods needed for your projects, share your code here so that it would be
beneficial for other developers.
You can find the source code of the extension methods from
the following URLs:
No comments:
Post a Comment