Extension methods

Extension methods are static methods that can be invoked using the instance method syntax. In effect, extension methods make it possible for us to extend existing types and constructed types with additional methods.

For example, we can define an extension method as follows:

public static class MyExtensions
{
public static bool IsCandy(this Product p)
{
if (p.ProductName.IndexOf("candy") >= 0)
return true;
else
return false;
}
}

In this example, the static method IsCandy takes a this parameter of Product type, and searches for the word candy inside the product name. If it finds a match, it assumes this is a candy product and returns true. Otherwise, it returns false, meaning this is not a candy product.

To simplify the example, we put this class inside the same namespace as our main test application, TestNewFeaturesApp. Now, in the program, we can call this extension method like this:

if (product.IsCandy())
Console.WriteLine("yes, it is a candy");
else
Console.WriteLine("no, it is not a candy");

It looks as if IsCandy is a real instance method of the Product class. Actually, it is a real method of the Product class, but it is not defined inside the Product class. Instead, it is defined in another static class.

Not only does it look like a real instance method, but this new extension method actually pops up when a dot is typed following the product variable. The following image shows the intellisense of the product variable within Visual Studio 2008.

Extension methodsLINQanonymous types

Under the hood in Visual Studio 2008, when a method call on an instance is being compiled, the compiler first checks to see if there is an instance method in the class for this method. If there is no matching instance method, it looks for an imported static class, or any static class within the same namespace. It also searches for an extension method with the first parameter that is the same as the instance type (or is a super type of the instance type). If it finds a match, the compiler will call that extension method. This means that instance methods take precedence over extension methods, and extension methods that are imported in inner namespace declarations take precedence over extension methods that are imported in outer namespaces.

In our example, when product.IsCandy() is being compiled, the compiler first checks the Product class and doesn't find a method named IsCandy. It then searches the static class, MyExtensions, and finds an extension method with the name IsCandy, and with a first parameter of the type, Product.

At compile time, the compiler actually changes product.IsCandy() to this call:

MyExtensions.IsCandy(product)

However, in the source code, this method is the same as another method defined inside the Product class, and that is why it is called an extension method.

Surprisingly, extension methods can be defined for sealed classes. In our example, you can change the Product class to be sealed, and it still runs without any problem. This gives us great flexibility to extend system types, because many of the system types are sealed.

On the other hand, extension methods are less discoverable, and are harder to maintain, so they should be used with great caution. If your requirements can be achieved with an instance method, one should never define an extension method to do the same work.

Not surprisingly, this new feature is again a Visual Studio 2008 compiler feature, and compiled assembly is a valid .NET 2.0 assembly.

Extension methods are the base of LINQ. We will discuss the various extension methods defined by .NET 3. in the namespace System.Linq, later.

Now, the Program.cs file should like this:

using System;
LINQextension methodsusing System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestNewFeaturesApp
{
class Program
{
static void Main(string[] args)
{
// valid var statements
var x = "1";
var n = 0;
string s = "string";
var s2 = s;
s2 = null;
string s3 = null;
var s4 = s3;
/*
string x = "1";
int n = 0;
string s2 = s;
*/
// invalid var statements
/*
var v;
var nu = null;
var v2 = "12"; v2 = 3;
*/
//object initializer
/*
Product p = new product(1, "first candy", 100.0);
Product p = new Product();
p.ProductID = 1;
p.ProductName = "first candy";
p.UnitPrice=(decimal)100.0;
*/
Product product = new Product
{
ProductID = 1,
ProductName = "first candy",
UnitPrice = (decimal)100.0
};
var arr = new[] { 1, 10, 20, 30 };
// collection initializer
List<Product> products = new List<Product> {
new Product {
ProductID = 1,
ProductName = "first candy",
UnitPrice = (decimal)10.0 },
new Product {
ProductID = 2,
ProductName = "second candy",
UnitPrice = (decimal)35.0 },
new Product {
ProductID = 3,
ProductName = "first vegetable",
UnitPrice = (decimal)6.0 },
new Product {
ProductID = 4,
ProductName = "second vegetable",
UnitPrice = (decimal)15.0 },
new Product {
ProductID = 5,
ProductName = "third product",
UnitPrice = (decimal)55.0 }
};
// anonymous types
LINQextension methodsvar a = new { Name = "name1", Address = "address1" };
var b = new { Name = "name2", Address = "address2" };
b = a;
/*
class __Anonymous1
{
private string name;
private string address;
public string Name {
get{
return name;
}
set {
name=value
}
}
public string Address {
get{
return address;
}
set{
address=value;
}
}
}
*/
// extension methods
if (product.IsCandy()) //if(MyExtensions.IsCandy(product))
Console.WriteLine("yes, it is a candy");
else
Console.WriteLine("no, it is not a candy");
}
}
public sealed class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public decimal UnitPrice { get; set; }
}
public static class MyExtensions
{
public static bool IsCandy(this Product p)
{
if (p.ProductName.IndexOf("candy") >= 0)
return true;
else
return false;
}
}
}

In this example, we have

  • Defined several var type variables
  • Defined a sealed class Product
  • Created a product list
  • Created a product with the name of "first candy"
  • Defined a static class, and added a static method IsCandy with a this parameter of the type Product, to it making this method an extension method
  • Called the extension method on the candy product, and printed out a message according to its name

If you run the program, the output will look like this:

Extension methodsLINQanonymous types
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset