views:

375

answers:

6

Looking at some code examples for HtmlHelpers, and I see declarations that look like:

public static string HelperName(this HtmlHelper htmlHelper, ...more regular params )

I can't remember seeing this type of construct any where else - can someone explain the purpose of the "this"? I thought that by declaring something public static meant that the class did not need to be instantiated - so what is "this" in this case?

+6  A: 

It is used for extensionmethods. Basically you 'glue' the Helpername to the htmlHelper object so you can say:

new HtmlHelper().HelperName(...more regular params);
Henrik Jepsen
+48  A: 

This is the syntax for declaring extension methods, a new feature of C# 3.0.

An extension method is part code, part compiler "magic", where the compiler with the help of intellisense in Visual Studio make it appear that your extension method is actually available as an instance method on the object in question.

Let me give an example.

There's no method on the String class that is named GobbleGobble, so let's create an extension method:

public static class StringExtensions
{
    public static void GobbleGobble(this string s)
    {
        Console.Out.WriteLine("Gobble Gobble, " + s);
    }
}

The class name is just my naming convention, it isn't necessary to name it like that, but it has to be static, as do the method.

After declaring the above method, you can, in Visual Studio, type this:

String s = "Turkey Baster!";
s.

after the dot, wait for intellisense, and notice there is a GobbleGobble method there, complete the code like this:

String s = "Turkey Baster!";
s.GobbleGobble();

Important: The class where the extension method is declared must be available to the compiler and the intellisense processor in order for intellisense to show the method. If you type in GobbleGobble manually, and use the Ctrl+. shortcut, it will not help you get the right using directives into the file.

Notice that the parameter to the method has disappeared. The compiler will silently move around the important bits, which are:

String s = "Turkey Baster!";
s.GobbleGobble();
^     ^
|     +-- the compiler will find this in the StringExtensions class
|
+-- will be used as the first parameter to the method

Thus, the above code will be transformed by the compiler to this:

String s = "Turkey Baster!";
StringExtensions.GobbleGobble(s);

So at call-time, there's nothing magical about it, it's just a call to a static method.

Note that if your extension method declares more than one parameter, only the first supports the this modifier, and the rest has to be specified as part of the method call as normal:

public static void GobbleGobble(this string value, string extra)
{                                            |              |
    ...                                      |              |
}                                            |              |
                                             |              |
+--------------------------------------------+              |
|                                                           |
v                                                           |
s.GobbleGobble("extra goes here");                          |
                        ^                                   |
                        |                                   |
                        +-----------------------------------+

Extension methods was added in part due to Linq, where the Linq syntax of C# will look for appropriately named extension methods for the objects in play, which means you can "introduce" Linq-support into any type of class by just declaring the right extension methods. Of course, full Linq support is a lot of work, but it is possible.

Also, extension methods by themselves are really useful, so read up on it.

Here's a few links:

Lasse V. Karlsen
+1 - An excellent explanation!
Shaihi
stop posting such awesome answers that make all my answers look sloppy and incomplete by comparison! *shame on you sir -- shame!*
Jeff Atwood
Pish tosh, you shouldn't be answering anyway, you should be making me a nice new diagram editor already! :) (oh, and thank you for the praise kind sir!)
Lasse V. Karlsen
Oh, and for the "Gobble Gobble" reference, here's a link: http://www.youtube.com/watch?v=ztfK4-sIoFk (@1:00)
Lasse V. Karlsen
I'm definitely going to start using the term "Gobble Gobble Magic".
chris
learned something new, thanks!
Jage
+3  A: 

That would be an Extension Method. They allow you to "extend" a class via static methods that live outside the original class.

For example, say you have a helpful string method that you use all the time...

public int CountAllAs(string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}

And you call it...

string allAs = "aaaA";
int count = CountAllAs(allAs);

That's not too bad. But with a small change, you could make it an Extension method and the call would be a little prettier:

public static int CountAllAs(this string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}

And then call it...

string allAs = "aaaA";
int count = allAs.CountAllAs();
Justin Niessner
+2  A: 

Extensions Methods...

...are a fantastic way to include functionality like if you where using the decorator pattern, but without the pain of refactoring all your code, or using a different name of a common type.

public static class Extensions
{
     public static string RemoveComma(this string value)
     {
         if (value == null) throw new ArgumentNullException("value");
        return value.Replace(",", "");
    }
}  

So you can use this code, anywhere in you app.

Console.WriteLine(“Hello, My, Friend”.RemoveComma())

>> Hello My Friend

So the this command attribute mean the type that the extension will be “added”, and let you work with the value as if it was passed as parameter.

Fraga
+1  A: 

After extension methods, I've been using them like crazy.. here is a few I use constantly..

public static T ChangeType<T>(this object obj)
{
  return (T)Convert.ChangeType(obj, typeof(T));
}

Works like this..

int i = "123".ChangeType<int>();
bool valid = "bool".ChangeType<bool>();
int id = dataSet.Tables[0].Rows[0]["Id"].ChangeType<int>();

Yeah, it shows up on every single object, can be annoying but since I use this for pretty much every data type, it helps to just attach it an object rather than duplicating it for every data type possible.

public static string ToXml(this object serializableObject)
{
    var aMemStr = new MemoryStream();
    try
    {
        var serializer = new XmlSerializer(serializableObject.GetType());
        serializer.Serialize(new XmlTextWriter(aMemStr, null), serializableObject);
        return Encoding.UTF8.GetString(aMemStr.ToArray());
    }
    finally { if (aMemStr != null) { aMemStr.Dispose(); } }
}

string xml = dataSet.ToXml();

public static T ToObject<T>(this string xmlString)
{
    var aStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString));
    try { return (T)new XmlSerializer(typeof(T)).Deserialize(aStream); }
    finally { if (aStream != null) { aStream.Dispose(); aStream = null; } }
}

DataSet dataSet = xml.ToObject<DataSet>();
LeeHull