#1,218 – C# 6.0 – Using Expression-Bodied Property Getters

In addition to using expression-body definitions for method bodies in C# 6.0, you can use an expression-body definition to implement the getter of a read-only auto-property.

For example:

        public string Name { get; protected set; }
        public int Age { get; set; }

        public string BackwardsName => new string(Name.Reverse().ToArray());

The presence of the expression-body definition tells the compiler that this is a property with a getter, rather than a field.

Advertisement

#1,217 – C# 6.0 – Using Expression-Bodied Methods

In C# 5.0, you could use a lambda expression wherever a delegate instance was expected.  For example:

            Func doubleMyNumber = (i) => 2 * i;

In C# 6.0, you use something similar for the body of a function member, known as an “expression-body definition” to define the method. This simplifies the syntax for simple methods.  For example:

    public class Dog
    {
        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public string Name { get; protected set; }
        public int Age { get; set; }

        public void AgeIncrement() => Age++;
        public int AgeInDogYears() => Age * 7;
    }

#1,191 – Lambda Can’t Capture ref or out Parameters

Lambda expressions can make use of variables declared in a containing scope, i.e. outside of the expression itself.  They cannot, however, use variables that are defined as ref or out parameters in an outer scope.

In the example below, it’s a compile-time error to include the valOut parameter in the lambda expression.

        static void SomeMethod(int valIn, out int valOut)
        {
            int local;

            Action doCalc = () =>
            {
                local = valIn * 2;   // this is ok
                valOut = valIn * i;  // this is not--compile-time error
            };
        }

As an alternative, you can assign a value returned by the lambda to an out parameter.

        static void SomeMethod(int valIn, out int valOut)
        {
            // Ok to assign result of lambda to
            // out parameter
            Func<int> doCalc2 = () => valIn * 2;
            valOut = doCalc2();   // Allowed
        }

#1,190 – A Lambda Expression Can Be Recursive

A lambda expression can be recursive.  That is, it can invoke the same delegate that the lambda is being assigned to.  As with any recursive method, you need to make sure that there is termination logic to prevent the recursion from continuing indefinitely.

Below is an example of a simple recursive lambda expression.

            // Must assign delegate so that we can
            // reference it in lambda
            Action<int> countdown = null;
                
            countdown = (i) =>
            {
                if (i > 0)
                { 
                    Console.WriteLine(i);
                    countdown(i-1);
                }
            };

            countdown(5);

1190-001

#1,189 – Lambda Expression Can Capture Static Data

A lambda expression set within a static method can make use of a class’ static data.  If the static data changes after the lambda is defined, invoking the lambda later will reflect the new (modified) static data.

Suppose that we have a Dog.SetStaticLambda method that defines a lambda using some static data:

    public class Dog
    {
        public string Name { get; set; }

        public Dog(string name)
        {
            Name = name;
        }

        public static string DogMotto;

        private static Action myStaticLambda;

        public static void SetStaticLambda()
        {
            myStaticLambda = () => Console.WriteLine("Motto: {0}", DogMotto);
        }

        public static void InvokeStaticLambda()
        {
            myStaticLambda();
        }
    }

Below, we make use of these methods. Note that if we invoke the lambda after changing the static data, the new data is used.

            Dog.DogMotto = "Serving mankind for generations";
            Dog.SetStaticLambda();
            Dog.InvokeStaticLambda();  // Serving..

            Dog.DogMotto = "We want more treats";
            Dog.InvokeStaticLambda();  // Want more..

1189-001

#1,188 – Lambda Expression Can Capture Instance Data

A lambda expression set within an instance method can make use of instance data within the object.  If the instance data changes after the lambda is defined, invoking the lambda later will reflect the new (modified) instance data.

Suppose that we have a Dog.SetLambda method that defines a lambda using some instance data:

    public class Dog
    {
        public string Name { get; set; }

        public Dog(string name)
        {
            Name = name;
        }

        private Action myLambda;

        public void SetLambda()
        {
            myLambda = () => Console.WriteLine("Dog is {0}", Name);
        }

        public void InvokeLambda()
        {
            myLambda();
        }
    }

Below, we make use of these methods. Note that if we invoke the lambda after changing the instance data, the new data is used.

            Dog d = new Dog("Bowser");
            d.SetLambda();
            d.InvokeLambda();  // Bowser

            d.Name = "Lassie";
            d.InvokeLambda();  // Lassie

1188-001

#1,187 – Using a Lambda Expression When Adding to an Invocation List

Recall that an instance of a delegate can refer to more than one method (delegates are multicast).  You can use anonymous methods to declare a new instance of a delegate or to add methods to a delegate’s invocation list.

Since lambda expressions supersede anonymous methods, you can also use lambdas to initialize a delegate or to add to its invocation list.

        private delegate void StringHandlerDelegate(string s);

        static void Main(string[] args)
        {
            // Declare new delegate instance, with lambda
            // as its invocation list
            StringHandlerDelegate del1 = 
                (s) => Console.WriteLine(s);

            // Now add a 2nd method to delegate, also using
            // lambda expression
            del1 +=
                (s) => Console.WriteLine(new string(s.Reverse().ToArray())); 

            // When we invoke the delegate, both lambdas
            // are invoked
            del1("Mairzy Doats and Dozy Doats");

            Console.ReadLine();
        }

1187-001

#1,182 – Capturing a for Loop Variable in a Lambda Expression

If you capture a variable in a lambda expression that is declared within the initializer of a for loop, the results may not be what you expect.  Recall that the value of a captured variable is evaluated when a delegate is invoked, rather than when it is assigned.  If you therefore invoke the delegate after all iterations of the loop have executed, the value of the captured variable will be whatever the final value of the variable was.

Below, notice that the same value is displayed during each invocation of the delegate.

            Action[] dels = new Action[3];

            for (int i = 0; i < 3; i++)
                dels[i] = () => Console.WriteLine(i + 1);

            // Prints 4/4/4, rather than 1/2/3
            foreach (Action d in dels)
                d();

1182-001

#1,181 – Instantiating an Object within a Lambda Expression

You can create instance of objects within lambda expression.  You can also optionally return that instance as the result of the expression.

            // Delegate set to dog-creating lambda
            Func<string,Dog> dogCreator = s => {
                Dog d = new Dog(s);
                d.Bark();
                return d;
            };

            Dog d1 = dogCreator("Lassie");

            Thread.Sleep(3000);  // wait 3 secs

            Dog d2 = dogCreator("Kirby");

            // Dump out creation time info
            Console.WriteLine(d1);
            Console.WriteLine(d2);

1181-001

#1,180 – Lambda Expressions Can Modify Captured Variables

When a variable is captured by inclusion in a lambda expression, the expression is free to modify the value of the captured variable, assuming that the variable is modifiable in the scope in which the lambda is defined.

            int localVariable = 10;

            Action<int> adder = i => localVariable += i;

            Console.WriteLine(string.Format("local at start: {0}", localVariable));
            adder(5);
            Console.WriteLine(string.Format("after calling adder, local: {0}", localVariable));

1180-001