Extension Methods

In my series on the new C# features, I had previously blogged about –

In this post, I will be talking about Extension methods. Extension methods allow new methods to be added to an existing class without having to actually extend the class using inheritance.

For instance, if you wanted to add a function called ReverseString to the String class, you can add it without creating a new class that inherits from String. Of course, String being a sealed class cannot be extended and adding a function to it is not possible via inheritance.

The syntax for doing this looks like this –

public static string ReverseString(this string str)
{
   //code to reverse the string
}

Notice that the function has to be static and it takes this followed by the type to which the extension method needs to be added to as the first parameter.

Intellisense

Once an extension method has been created, it shows up in Intellisense – which is quite handy.

image

Notice that the icon for an extension method is different to the usual ones.

Usage Rules

When using extension methods, there are few rules that need to be followed –

  • Extension methods have to be declared in a static function in a top level static class
  • The first parameter has to start with “this” and it cannot appear multiple times in the parameters
  • The keyword “this” must be followed by the type that needs to be extended. The type can be an interface, abstract class, a concrete class or even a sealed class.
  • You cannot use things like “ref” and “out” with “this”
  • You cannot extend Properties, Events or operators (something for the future version, perhaps 🙂 ?)

Ambiguity

If you have the same extension method declared in two separate static classes, then the compiler will throw an error message saying that the call is ambiguous when the actual function is called in code. Unlike namespaces that help resolve classes that share the same name, there is no way to resolve function name clashes.

Extension methods that currently exist

.NET framework 3.5 comes loaded with a lot of extension methods. For instance, the IEnumerable interface has extension methods such as Aggregate, Average, Concat, Count, GroupBy, etc. A lot of these extension methods are essential for implementing LINQ (which will be covered in a future post).

More Examples

Extension methods can have additional parameters, as this example shows –

public static string ExtensionMethodWithParameter(
                      this string str, 
                      string value)
{
    //Do nothing, it is just an example
    return str;
}

You can also add extension methods to arrays –

public static float MyAverage(this int[] intArray)
{
    float sum = 0;
    foreach (var element in intArray)
    {
        sum += element;
    }
    return sum / intArray.Length;
}

They can also be added to the base class of them all – “object”. For example, this function converts any object into an Xml representation, based on its properties –

//Simple, shallow implementation. Converts any object to Xml
public static string ToXml(this object o)
{
    Type myType = o.GetType();

    XmlDocument xmlDoc = new XmlDocument();
    XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration(
        "1.0", "utf-8", null);

    // Create the root element
    XmlElement rootNode = xmlDoc.CreateElement(
        XmlConvert.EncodeName(myType.Name));
    xmlDoc.InsertBefore(xmlDeclaration, 
        xmlDoc.DocumentElement);
    xmlDoc.AppendChild(rootNode);


    var properties = myType.GetProperties();
    foreach (PropertyInfo prop in properties)
    {

        XmlElement childNode = 
            xmlDoc.CreateElement(prop.Name);
        childNode.AppendChild(
            xmlDoc.CreateTextNode(
            prop.GetValue(o, null).ToString()));

        rootNode.AppendChild(childNode);
    }


    return xmlDoc.InnerXml;

}

Anonymous Types in C# 3.0

Anonymous Types allows developers to create a new type on the fly without an explicit declaration of the class. They can easily be explained with the help of an example –

var person0 = new
{
    FirstName = "Mahesh",
    LastName = "Krishnan",
    Height = 182
};
var person1 = new
{
    FirstName = "John",
    LastName = "Doe",
    Height = 165
};
var person2 = new
{
    LastName = "Doe",
    FirstName = "John",
    Height = 175
};

Notice that the syntax makes use of both Implicitly typed variables as well as Object initialization methods that were explained in earlier posts. The new keyword usually is followed by the type that we wish to create, but while creating anonymous types, this is left blank and is followed immediately with a curly bracket as shown above. When the C# compiler sees a new anonymous class declared, it creates a new class under the covers. If we look at the types of these anonymous classes, they will look something like this –

<>f__AnonymousType0`3[System.String,System.String,System.Int32]
<>f__AnonymousType0`3[System.String,System.String,System.Int32]
<>f__AnonymousType1`3[System.String,System.String,System.Int32]

Notice that C# automatically generated the same Type for both person0 and person1, as they contained the same elements in the same order. person2 had a different order of the same elements and so, C# created a new type for it.

Usage rules/restrictions

  • The properties in Anonymous types are all read only and therefore cannot be modified once they are created.
  • Anonymous types cannot have methods.
  • Anonymous types are always assigned to vars. This allows the compiler to assign the right type. But,  if Anonymous types are used as return values or as parameters in a function, they will have to be passed in as Objects, as var is not a proper type

Projection

Anonymous types also supports Projection. So, if we have a declaration as shown below –

var LastName = "Nurk";
var FirstName = "Fred";

var person4 = new { LastName, FirstName};

then a new Anonymous type will be created with the read only properties LastName and FirstName. C# automatically projects the names of the variables to the names of properties in the anonymous class.

This also works while using objects, as shown below –

Person personObject = new Person
{
    LastName = "Doe",
    FirstName = "Jane",
    Height = 156
};
var projectionFromClass = new
{
    personObject.FirstName,
    personObject.LastName
};

In this case, the object projectionFromClass will have an anonymous type that picks up the property names FirstName and LastName, which will hold the values “Jane” and “Doe”.

Implicitly typed arrays in C# 3.0

After my C# 3.0 session at the Vic .NET Hands on day, there were several requests to post my examples in greater detail. So, I thought I’d continue the posts I started earlier on the same topic. The first 3 topic were –

Over a series of several posts, I plan to cover the remaining topics –

  • Implicitly Typed Arrays
  • Anonymous Types
  • Auto Implemented Properties
  • Extension Methods
  • Lambda Expression
  • LINQ
  • Expression Trees
  • Partial Methods

In this post, I plan to talk about Implicitly typed arrays. In C# 3.0, as with Implicitly typed local variables, you can also create an array of objects that use type inference to determine what array type they are. So the following statements would create an array of ints and doubles respectively, based on the types of the elements specified within the curly brackets –



//Examples of type inference
var myIntegers = new[] { 1, 2, 3, 4, 5 };
var myDoubles = new[] { 1, 2.1, 3.2, 4.3 }; 

Although the examples show primitive types as array elements, they are not limited to value types. The compiler will automatically infer the type based on the elements and assign it to the correct array type on the left hand side. The example below shows elements using a class Dog and its equivalent in C# 2.0

var myPets = new[] 
    { 
      new Dog( "Spike" ), 
      new Dog( "Snoopy" ) 
    };
 
Dog[] pets = new Dog[2];
pets[0] = new Dog("Spike");
pets[0] = new Dog("Snoopy"); 

What you cannot do

For starters, you cannot mix and match types within your array. You also cannot have nulls when you have an array of value types. So, both the statements shown below are not legal –

//Cannot mix types
var mixedArray = new[] { 0, "one", 2, "three" }; 
//Cannot have nulls, when you mix with value types
var arrayWithNulls = new [] { 1, 2, null };

However, the following statement is acceptable, as it forces the compiler to create an array of nullable ints –

var arrayWithNulls = new[] { (int?)1, 2, 3, null };

Inference when using types from the same inheritance tree

When you have elements in the array that have types from the same inference tree, at least one of the types in the list have will have to be base class. For example, if we have the inheritance as shown below –

image

then, the first statement will not work, while the second one will –


var myPets = new[] { new Cat(), new Dog() } ;
var myPets1 = new[] { new Cat(), new Pet() } ;

If you want to create an array of IAnimal elements, then at least one of the elements in the array will have to be explicitly typed to an IAnimal as shown below –



IAnimal dog = new Dog();
var myPets2 = new[] { dog, new Cat() };

You cannot call it Implicitly typed, then. Can you? 🙂

Object Initialization in C# 3.0

In older versions of C# when you create a new object and had to initialize some of its members, you had to write code similar to this –

Name name = new Name();
name.FirstName = “Fred”;
name.LastName = “Nurk”;

To make this sort of initialization easier, C# 3.0 introduces new syntax as shown below –

//Initialization with empty constructor
Name name = new Name
             { FirstName = “Fred”,
               LastName = “Nurk” 
             };

The syntax also allows constructors with parameters –

//Intialization with constructor parameter
Name name = new Name(someParameter)
            {
                FirstName = “Fred”,
                LastName = “Nurk” 
            };

You can also do nested initialization as shown below –

//Nested initialization
Customer customer = new Customer
{
    CustomerName = new Name 
       { FirstName = “Fred” },
       Address = “400, Somwhere”
};

The syntax is pretty straight forward. You can initialize any public Property or member variable, by specifying the name of the Property/variable and initializing it with a = operator. More than one member can be initialized by using the comma operator. The only thing you cannot do is call a method or initialize a private member inside the initializer.