#1,193 – yield Statement and try/catch Blocks

The yield return statement is used when defining an iterator to generate the next element within a sequence (IEnumerable).  You cannot include a yield return statement in any of the following places:

  • within a try block that has a catch clause
  • within a catch block
  • within a finally block

You can include a yield return statement within a try block that only has a finally block.

        private static IEnumerable<int> IntsAndTheirDoubles()
        {
            for (int i = 1; i <= 5; i++ )
            {
                yield return i;
                try
                {
                    // Error: Cannot yield a value in the body of a try block
                    //   with a catch clause
                    yield return 2 * i;
                }
                catch (Exception xx)
                {
                    Console.WriteLine("Uh-oh");
                }
            }
        }

#1,192 – Following the TryParse Pattern

The int.TryParse method does the same thing as the int.Parse method, but without throwing an exception.  Instead, it returns a boolean value indicating whether the method succeeded or not and writes the result to an out parameter.

You might follow the same pattern when writing your own code, providing a method that throws an exception on failure and a TryXxx version of the method that returns a boolean indicating whether the method succeeded.  Below is an example.

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

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

        public bool TryBark(out string barkSound)
        {
            bool success = false;
            barkSound = "";

            if (Age <= 10)
            {
                success = true;
                barkSound = "Woof";
            }

            return success;
        }

        public string Bark()
        {
            string barkSound;

            if (!TryBark(out barkSound))
                throw new Exception("This dog can't bark");
            return barkSound;
        }
    }

#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

Follow

Get every new post delivered to your Inbox.

Join 457 other followers