Bagikan melalui


Anonymous methods and closures in C#

Anonymous Method

One of the new features in C#2.0 being shipped in with Whidbey is anonymous methods. Though this at first glance looks like an easy way of creating delegates, where instead of having to create a new function which the delegate will call you can pass the code inline.

Before C#2.0

class

MyClass
{
delegate void MyDelegate();
static public void Function()
{
Console.WriteLine("I'm called");
}

     static void Main()
{
MyDelegate writeMessage = new MyDelegate(Function);
writeMessage();
}
}

With C#2.0 and anonymous methods: the Function is eliminated and the same piece of code can be written more elegantly as follows

class MyClass
{
    delegate void MyDelegate();
    static void Main()
{
        MyDelegate writeMessage = delegate ()
{ Console.WriteLine("I'm called"

);
};

writeMessage();
}
}

For more details on Anonymous methods check out https://msdn.microsoft.com/msdnmag/issues/04/05/c20/default.aspx.

However, there is more to it than just getting a short hand way of writing code. With anonymous methods you can now do a lot of things in C# which are commonly done in Functional languages. Consider the code below which is actually a function generator.

class Program
{
delegate void MyDelegate<T>(T t);
enum FunctionType
    {
WithPrefix,
WithoutPrefix
}
static MyDelegate<T> FunctionGenerator<T>(FunctionType fType)
{
int i = 0; if (fType == FunctionType.WithPrefix)
{
           return delegate (T t)
{ Console.WriteLine(i.ToString() + ": "

+ t.ToString());
i++;

};
}
        else
        {
return delegate (T t)
{ Console.WriteLine(

t.ToString());
};

}
}

    static void Main(string[] args)
{
MyDelegate<int> mdWith = FunctionGenerator<int>(FunctionType.WithPrefix);
mdWith(5);
mdWith(5);

MyDelegate<string> mdWithout = FunctionGenerator<string>(FunctionType.WithoutPrefix);
mdWithout("Hello");
}
}

The output is
0 : 5
1 : 5
Hello

As in the above piece of code you can create Function Generator that actually return different implementations based on requirement. For another interesting sample see Don Box's blog https://pluralsight.com/blogs/dbox/archive/2005/04/17/7467.aspx

Closure

For any languages which allow passing around functions as arguments or functions returning another function the Closure abstraction is very important. For more info on Closure see https://en.wikipedia.org/wiki/Closure_(computer_science). C#2.0 supports closure by the use of anonymous methods.

Closure is a function along with its lexical environment (available variables and their values) when the function is created.

int i = 10; 
return delegate (T t)
{ Console.WriteLine(i.ToString() + ": "

+ t.ToString());
};
 

Since the variable i was available with the value 0 when the Anonymous method was created, inside the method, i will be available with the same value when the method is called via the delegate.

From the definition of Closure it can be inferred that Closure remembers the values of the variables during its creation. However in C# the outer local variable (i in this case) is shared with the anonymous method by creating it on the heap. This means any change to it in the anonymous method changes the original value and when the method is called the second time it gets the modified value of i as 1 (see second line of output). This leads many to argue that anonymous method is not actually a Closure as by its definition the value of a variable at the time of creation of the Closure should be remembered and not modifiable.

Check out the link https://blogs.msdn.com/brada/archive/2004/08/03/207164.aspx on how the implementation of Anonymous methods in C# have led to interesting issues.

Comments

  • Anonymous
    September 16, 2005
    This is the my third post on the series of post I am making on C#3.0 after it got declared on PDC. See...

  • Anonymous
    September 16, 2005
    This is the my third post on the series of post I am making on C#3.0 after it got declared on PDC. See...

  • Anonymous
    September 16, 2005
    This is the my third post on the series of post I am making on C#3.0 after it got declared on PDC. See...

  • Anonymous
    December 02, 2005
    This leads many to argue that anonymous method is not actually a Closure as by its definition the value of a variable at the time of creation of the Closure should be remembered and not modifiable.

    Your definition of closure is faulty. A closure simply captures the value of variable, whether it's an l-value or an r-value.

    Other languages, purported to have closures, exhibit the same behavior. It's also rather a moot point, since C#'s implementation is more expressive than your definition of closures. I don't see how adding restrictions to anonymous delegates would improve C#.

  • Anonymous
    December 06, 2005
    Wesner I do agree with you now :)

    See another of my post on the same topic in http://blogs.msdn.com/abhinaba/archive/2005/10/18/482180.aspx

    In the comment section (which is pretty long) Dan Muller (author on the famed C2 wiki) convinced me that my definition of closures was not correct. I interpreted closure to be a name/value mapping as opposed to name/variable mapping as it really is.

    I now completely agree that C# does implement true closure. However, what really intrigues me is that people like Brad Adams (http://blogs.msdn.com/brada/default.aspx) say C# do not implement closure....

  • Anonymous
    April 12, 2007
    The question isn't whether or not C# closures are "real"... it is what do you intend to do with your closures.Functional programmers that use Haskel or ML are used to immutable variables, which makes the two definitions collapse into one... it doesn't matter if you get a value or a reference.Imperative programmers (and that includes those who program in non-strict functional capable languages such as Lisp) are used to the distinction.The issue that arises with mutable variables is that thread safety becomes a problem for the closure to manage (and thus increases complexity and leads some to call them "not-real closures"), whereas with immutable variables the value you capture can't be impacted by other threads (and for some, this is a requirement of "real closures").As long as you are careful to create a new variable instance that won't be modified by further threads (a local introduced in the block defining the anonymous method will work just fine) you can avoid the thread issues, while not removing the possibilities that mutable variables hold (including all the potential bugs).

  • Anonymous
    January 20, 2008
    PingBack from http://websitescripts.247blogging.info/i-know-the-answer-its-42-anonymous-methods-and-closures-in-c/

  • Anonymous
    August 08, 2008
    The question isn't whether or not C# closures are "real"... it is what do you intend to do with your closures. thanks..