#1,179 – Captured Variable’s Lifetime Matches Delegate

When a variable is captured by inclusion in a lambda expression, the lifetime of that variable becomes the lifetime of the delegate that the lambda is assigned to.

In the example below, we have a local variable whose scope is the body of the SomeFunction method.  We then use this local variable in a lambda expression that is assigned to a delegate instance.  After we exit SomeFunction, we can invoke the delegate and see that the variable defined in SomeFunction is still accessible.

        static Action aDelegate;

        static void Main(string[] args)
        {
            SomeFunction();

            // After call, invoke delegate to show
            // that magicNum is still alive
            aDelegate();

            Console.ReadLine();
        }

        static void SomeFunction()
        {
            int magicNum = 42;

            // Assign delegate to print value of local
            // variable
            aDelegate = () => Console.WriteLine(magicNum);
        }

1179-001

#1,178 – Captured Variables Are Evaluted when a Delegate Is Invoked

A captured variable is a variable declared outside of the scope of a lambda expression, but used within the expression.

            int magicNum = 20;
            Func<int, int> mulByMagic = i => i * magicNum;

            Console.WriteLine(mulByMagic(10));  // 200

Note that the value used for a captured variable is whatever value is current when the associated delegate is invoked, rather than the value that the variable had when the lambda was defined.

            int magicNum = 20;
            Func<int, int> mulByMagic = i => i * magicNum;

            Console.WriteLine(mulByMagic(10));  // 200

            magicNum = 100;
            Console.WriteLine(mulByMagic(10));  // 1000

#1,177 – Lambda Expressions Can Reference Variables Declared Outside of Expression

A lambda expression can make use of its own parameters and local variable declarations.  For example:

            Action<int> act1 = (num) =>
            {
                for (int i = num; i < num + 2; i++)
                {
                    int result = i * 2 - 1;
                    Console.WriteLine(string.Format("{0}, {1}", i, result));
                }
            };

A lambda expression can also make use of a local variable or parameter declared outside of the lambda expression. For example:

        static void Main(string[] args)
        {
            DoSomething(4);
            Console.ReadLine();
        }

        static void DoSomething(int someParam)
        {
            int magicNum = 2;

            Action<int> act1 = (num) =>
            {
                for (int i = num; i < num + (magicNum * someParam); i++)
                {
                    int result = i * 2 - 1;
                    Console.WriteLine(string.Format("{0}, {1}", i, result));
                }
            };

            act1(5);
        }

1177-001

#1,176 – How an Expression Tree is Stored in Memory

You can assign a lambda expression to an expression tree, storing the expression in an instance of Expression<TDelegate> (e.g. Expression<Func<double,double>>).

Suppose that we store the expression to convert from fahrenheit to celsius:

            // Assign to expression tree
            Expression<Func<double, double>> fahrToCelsius =
                (f) => (f - 32.0) * 5.0 / 9.0;

We can now look at this element in memory, to see how this expression is stored. Expression<T> has a Body property that is of type Expression and represents the top-level of the expression tree.  The Expression’s NodeType property indicates the operator used in the expression.  In this example, the Body will be of type BinaryExpression, which has Left and Right properties which are also of type Expression and represent left and right sub-expressions.

This is shown below by examining the expression tree in the debugger for the fahrenheit to celsius expression shown above.

1176-001

#1,174 – Assigning a Lambda Expression to an Expression Tree

You can assign a lambda expression to either an instance of a delegate type or to an expression tree based on a compatible delegate type.  An expression tree is just an in-memory representation of an expression, encoding the expression as a tree.  This allows you to interact with the expression as a data structure.

            // Assign to delegate type
            Func<int, int> doubleMe = (i) => 2 * i;

            // Assign to expression tree
            // (using System.Linq.Expressions)
            Expression<Func<int, int>> doubleMeExpr = (i) => 2 * i;

#1,173 – Lambda Expression Can Be Just an Expression

You’ll often see lambda expressions written as either a single statement (no return value) or a block of statements (optional return value).

        static void SomeMethod(int i, string s)
        {
            // do something with int and string
        }

        static void Main(string[] args)
        {
            // Single statement
            Action<int, string> thing1 = (i, s) => SomeMethod(i, s);

            // Block of statements, no return value
            Action<int, string> thing2 = (i, s) =>
            {
                for (int i2 = i; i2 <= i + 10; i2++)
                    SomeMethod(i2, s);
            };

            // Block of statements with return value
            Func<int,int> thing3 = (i) =>
            {
                SomeMethod(i, "x");
                return i + 1;
            };
        }

A lambda expression can also be a single statement representing an expression whose type is assignment compatible with the return value of the delegate type being assigned to.

            // Expression
            Func<int, int> doubleMe = (i) => 2 * i;
            Console.WriteLine(doubleMe(42));

1173-001

#1,170 – You Can’t Unsubscribe from an Event Using a Lambda Expression

Suppose that you subscribe to an event using a lambda expression:

            Dog d = new Dog("Bowser");

            // NOTE: Barked is EventHandler<string>
            d.Barked += (s, e) => Console.WriteLine("Bark: {0}", e);

You cannot, however, unsubscribe using the same syntax. The -= operator shown below will be using a different anonymous method, so the original will not be removed from the event’s invocation list.

            // Not what you expect
            d.Barked -= (s, e) => Console.WriteLine("Bark: {0}", e); 

So the lambda expression syntax is fine–as long as you don’t need to unsubscribe from the event.  (More on that in a future post).

If you want to unsubscribe, but still use lambda syntax, you could persist the delegate instance.

            EventHandler<string> handler = (s, e) => Console.WriteLine("Bark: {0}", e);
            d.Barked += handler;

            // ...

            d.Barked -= handler;

#1,168 – Using a Lambda Expression as an Event Handler

You can use a lambda expression wherever a delegate instance is expected.  This includes using a lambda expression when defining an event handler.

        static void Main(string[] args)
        {
            Dog d = new Dog("Bowser");

            // Method #1 - Subscribe to Barked event using named method
            d.Barked += d_Barked;

            // Method #2 - Subscribe to Barked event using lambda expression
            d.Barked += (s, e) => { Console.WriteLine("My dog says {0}", e); };

            d.Bark();

            Console.ReadLine();
        }

        static void d_Barked(object sender, string e)
        {
            Console.WriteLine("Dog {0} just barked, saying {1}",
                ((Dog)sender).Name, e);
        }

1168-001

#947 – Specifying Lazy Instantiation Using a Lambda Expression

When you are declaring an object that will be lazily instantiated, you pass a delegate instance to the Lazy<T> constructor, where the delegate instance indicates a method to be called that will instantiate the underlying object.

For example, you could do the following:

        private static Lazy<Dog> dog1 = new Lazy<Dog>(CreateDefaultDog);
        private static Dog CreateDefaultDog()
        {
            return new Dog("Lassie");
        }

Very often, however, you’ll want to pass some parameter value to the delegate or just invoke one of the normal constructors for the object, passing one or more parameters to the constructor.  You can do this by just using a lambda expression, as follows:

        private static Lazy<Dog> dog2 = new Lazy<Dog>(() => new Dog("Lassie"));

#148 – Getting the Average of an Array of Custom Objects

If you want to calculate the average (mean) of a collection of objects stored in an array, you can use the IEnumerable.Average method.

The Average method allows passing in an indication of the function that should be used to calculate the numeric value from each object, which will be used in generating the average.  This function takes an object whose type matches the type of the array as an input parameter and returns a numeric value, used in generating the average.  It will be called once for each element of the array.

You could define a static function and pass a delegate to that function.

        static int AgeOf(Person p)
        {
            return p.Age;
        }

        // Example of calling Average on Person[] array
        double avgAge = folks.Average((Func<Person,int>)AgeOf);

Alternatively, you could use a lambda expression, avoiding the need to define a separate function.

            double avgAge = folks.Average(person => person.Age);