Wednesday, January 18, 2012

@C#: I love yield return

If you code in C#, you must know yield return. It's a feature of C# language itself, that is, the compiler does code re-writing.

I find it so useful. If it actually existed in the real world I would send flowers there. In particular, this feature alone lets me solve many multi-threading related issues.

Without too much talking, here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleTest
{
    class Program
    {
        IDisposable GetAccess(string tag)
        {
            return new MyDisposable(tag);
        }

        IEnumerable<int> GetStepByStep()
        {
            using (GetAccess("GetStepByStep"))
            {
                for (int i = 1; i < 5; ++i)
                {
                    if (i == 3)
                        throw new ArgumentException("i == 3. Error.");

                    Console.WriteLine("GetStepByStep is about to return {0}", i);
                    yield return i;
                }
            }
            Console.WriteLine("GetStepByStep exits.");
        }

        int Summator()
        {
            var res = 0;
            using (GetAccess("Summator"))
            {
                foreach (var el in GetStepByStep())
                    res += el;
            }

            return res;
        }

        void Run()
        {
            try
            {
                var res = Summator();
                Console.WriteLine("Res = {0}", res);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception: {0}", ex.Message);
                Console.WriteLine("Stack trace: {0}", ex.StackTrace);
            }
            finally
            {
                Console.WriteLine("Done.");
            }
        }

        static void Main(string[] args)
        {
            new Program().Run();
        }
    }

    class MyDisposable : IDisposable
    {
        string _tag;

        public MyDisposable(string tag)
        {
            _tag = tag;
            Console.WriteLine("MyDisposable.Constructor({0}) called.", tag);
        }

        public void Dispose()
        {
            Console.WriteLine("MyDisposable.Dispose() called. (Tag = {0})", _tag);
        }
    }
}


And the output:
MyDisposable.Constructor(Summator) called.
MyDisposable.Constructor(GetStepByStep) called.
GetStepByStep is about to return 1
GetStepByStep is about to return 2
MyDisposable.Dispose() called. (Tag = GetStepByStep)
MyDisposable.Dispose() called. (Tag = Summator)
Exception: i == 3. Error.
Stack trace:    at ConsoleTest.Program.d__0.MoveNext() in C:\dev\
zit\!PureTest\2012_01_18 Yield, States and Multitasking\ConsoleTest\Program.cs:l
ine 22
   at ConsoleTest.Program.Summator() in C:\dev\zit\!PureTest\2012_01_18 Yield, S
tates and Multitasking\ConsoleTest\Program.cs:line 36
   at ConsoleTest.Program.Run() in C:\dev\zit\!PureTest\2012_01_18 Yield, States
 and Multitasking\ConsoleTest\Program.cs:line 47
Done.
Press any key to continue . . .

P.S. That's actually a piece from functional approach. So, F# is the next primary language of mine.

No comments:

Post a Comment