Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can someone explain this C# lambda syntax?

Tags:

c#

I recently came upon a static method declared as:

public class Foo
{
  public static Func<HtmlHelper, PropertyViewModel, string> Render = (a, b) =>
  {
    a.RenderPartial(b);
    return "";
  };
}

Intellisense suggests the usage is (for example):

string s = Foo.Render(htmlHelper, propertyViewModel);

It would seem then that the following is equivalent:

public static string Render(HtmlHelper a, PropertyViewModel b)
{
  a.RenderPartial(b);
  return "";
}

A) What is the name of the first style? I realize it's using lambdas; it's the = sign that is tripping me up. I can't tokenize it ;)

B) If the two code blocks are equivalent, what is the benefit of using the former over the latter?

like image 555
Roatin Marth Avatar asked Jan 21 '10 23:01

Roatin Marth


3 Answers

Ok, for clarity I'm going to write the two out again (and slightly modify the method to make it shorter)

public static Func<HtmlHelper, PropertyViewModel, string> RenderDelegate = (a, b) =>
{
    return a.RenderPartial(b);
};

public static string RenderMethod(HtmlHelper a, PropertyViewModel b)
{
    return a.RenderPartial(b);
}

Firstly note that RenderDelegate is (as S. DePouw writes), just a fancy way of using lambda syntax to write the following:

public static Func<HtmlHelper, PropertyViewModel, string> RenderDelegate = 
delegate(HtmlHelper a, PropertyViewModel b)
{
    return a.RenderPartial(b);
};

The difference between RenderMethod and RenderDelegate is that RenderMethod is a method, wheras RenderDelegate is a delegate, or more specifically a field of type Delegate. This means that RenderDelegate can be assigned to.

What is a Delegate?

A delegate is a type. From the MSDN documentation:

A delegate is a type that defines a method signature, and can be associated with any method with a compatible signature.

Essentially you can think of a delegate as a reference / pointer to a method, however the method that the delegate points to has to match the signature that the delegate is expecting. So for example Func<HtmlHelper, PropertyViewModel, string> is a Delegate that expects methods with the signature string MyMethod(HtmlHelper, PropertyViewModel) and so we are able to assign methods with that signature to that delegate like this:

RenderDelegate = RenderMethod;

Its important to note the difference between the Delegate type (note the capital D) and the delegate keyword (lower case d). In your example your using the Func<> generic object to condense your code, however its kind of obscuring whats really going on here. Func<HtmlHelper, PropertyViewModel, string> is a type which inherits from Delegate, and you could use the delegate keyword to delcare an equivalent type:

delegate string MyFunction<HtmlHelper helper, PropertyViewModel string>;
static MyFunction RenderDelegate = RenderMethod;

Anonymous methods

When we assigned RenderDelegate in the first example, we didnt set RenderDelegate to an existing named method, instead we declared a new method in-line. This is known as an Anonymous Method and works because we are able to pass a code block (also declared using the delegate keyword) as a delegate parameter:

Lambda functions

Back to the original syntax - your example is using lambda syntax to delcare an anonymous delegate in a funny way. Lambda expressions are good way of declaring short inline methods which might commonly be used when dealing with lists, for example supposing we want to sort a list of HtmlHelper objects by their Name. The way of doing this is to pass a Delegate that compares two HtmlHelper objects to the lists Sort method, the sort method then uses that delegate to compare and sort the elements in the list:

static int MyComparison(HtmlHelper x, HtmlHelper y)
{
    return x.Name.CompareTo(y.Name);
}

static void Main()
{
    List<HtmlHelper> myList = GetList();
    myList.Sort(MyComparison);
}

To avoid having loads of short methods scattered around, you can use anonymous methods to delcare the sorting method in-line. Whats also really useful about this is that the in-line method has access to variables declared in the containing scope:

int myInt = 12;
List<HtmlHelper> myList = GetList();
myList.Sort(
    delegate (HtmlHelper x, HtmlHelper y)
    {
        return x.Name.CompareTo(y.Name) - myInt;
    });

Thats still fairly quite a lot of typing however, and so the lambda sytax was born and now you can do this instead:

List<HtmlHelper> myList = GetList();
myList.Sort((x, y) => {return x.Name.CompareTo(y.Name)});

Declaring "normal" methods in this way however seems to be completely pointless to me (and makes my eyes bleed)

Delegates are incredibly useful and are (among other things) the cornerstone of the .Net event system. Some more reading to clear things up a bit:

  • Delegates and events in C#
  • Anonymous methods (MSDN documentation)
  • Introduction to lambda expressions
like image 151
Justin Avatar answered Oct 31 '22 10:10

Justin


A) The style is that of using delegates. The following is equivalent:

public static Func<HtmlHelper, PropertyViewModel, string> Render = 
delegate(HtmlHelper a, PropertyViewModel b)
{
    a.RenderPartial(b);
    return "";
};

B) The benefit is that you could then treat Render as a variable within another method. In this particular instance, however, they're more or less the same benefits-wise (although the latter is a bit easier to comprehend).

like image 36
Doctor Blue Avatar answered Oct 31 '22 11:10

Doctor Blue


For the most part they seem functionally equivalent. In fact you can pass around a normal method as a variable.

But there are subtle differences like being able to redefine the function to be something else. It is probably also different if you're using reflection, e.g. it probably isn't returned in the list of methods on the class. (Not 100% sure on the reflection part)

The following shows passing a method as a variable as well as how the 2nd way allows redefining the Func that wouldn't be possible if it were a normal method.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(GetFunc());   //Prints the ToString of a Func<int, string>
        Console.WriteLine(Test(5));     //Prints "test"
        Console.WriteLine(Test2(5));    //Prints "test"
        Test2 = i => "something " + i;
        Console.WriteLine(Test2(5));    //Prints "something 5"
        //Test = i => "something " + i; //Would cause a compile error

    }

    public static string Test(int a)
    {
        return "test";
    }

    public static Func<int, string> Test2 = i =>
    {
        return "test";
    };

    public static Func<int, string> GetFunc()
    {
        return Test;
    }
}

This just got me thinking... if all methods were declared this way, you could have real first class functions in C#... Interesting....

like image 2
Davy8 Avatar answered Oct 31 '22 10:10

Davy8