Adapting C# 2.0 event code for C# 5.0 I came across this excellent post on delegates and event and tried to adapt it to C# 5.0L

namespace Bla
{
    public delegate void WorkStarted();
    public delegate void WorkProgressing();
    public delegate Task&lt;int&gt; WorkCompleted();

    public class Worker
    {
        public event WorkStarted Started;
        public event WorkProgressing Progressing;
        public event WorkCompleted Completed;

        public void DoWork()
        {
            Console.WriteLine("Worker: work started");
            if (Started != null)
                Started();

            Console.WriteLine("Worker: work progressing");
            if (Progressing != null)
                Progressing();

            Console.WriteLine("Worker: work completed");
            if (Completed == null) return;
            foreach (var del in Completed.GetInvocationList())
            {
                var wc = (WorkCompleted) del;
                var wc2 = wc;
                wc.BeginInvoke(delegate(IAsyncResult result)
                {
                    var grade = wc2.EndInvoke(result);
                    Console.WriteLine("Worker grade = {0}", grade.Result);
                },
                    null);
            }
        }
    }

    public class Boss
    {
        public async Task&lt;int&gt; WorkCompleted()
        {
            await Task.Delay(TimeSpan.FromSeconds(3));
            Console.WriteLine("Better...");
            return 5; // out of 10
        }
    }

    public class Universe
    {
        public static void WorkerStartedWork()
        {
            Console.WriteLine("Universe notices worker starting work");
        }

        public static async Task&lt;int&gt; WorkerCompletedWork()
        {
            await Task.Delay(TimeSpan.FromSeconds(10));
            Console.WriteLine("Universe pleased with worker's work");
            return 7;
        }

        private static void Main()
        {
            var peter = new Worker();
            var boss = new Boss();
            peter.Completed += boss.WorkCompleted;
            peter.Started += WorkerStartedWork;
            peter.Completed += WorkerCompletedWork;
            peter.DoWork();

            Console.WriteLine("Main: worker completed work");
            Console.ReadLine();
        }
    }
}


Could this be further improved?
There are indeed some things lacking to call this C#5 code: your delegates are not necessary.

The first two are easy: remove the delegate, make the event return EventHandler instead, call the event with Started(this, EventArgs.Empty) and change the method signature accordingly. This results in this:

public event EventHandler Started;

if (Started != null)
{
    Started(this, EventArgs.Empty);
}

public static void WorkerStartedWork(object sender, EventArgs e)
{
    Console.WriteLine("Universe notices worker starting work");
}


The same thing goes for Progressing.



The Completed event is more difficult but only because you made it so. In your Completed event you have 2 consumers at this point. All you have to do is change the signature to EventHandler, change the calling to

if(Completed != null)
{
    Completed(this, EventArgs.Empty);
}


And change all handlers to

public async void WorkCompleted(object sender, EventArgs e) { }


Now it will call every consumer and you don't have to mess around by looking at the invocation list anymore



Don't use the universe statically. Combined with events, that is just bound to cause memory problems. Instead I would make it an instance just like Worker and Boss and then connect its handlers to peter.



By making these changes to the WorkCompleted handlers you'll notice that you can't use Task anymore as a return type. That's true, events are forced to adhere to their void X(object, T) where T : EventArgs definition. Because of this, events are the only place where it is allowed to use async void.

This will cause your events to become fire-and-forget but there are ways around that as well if you don't want this.



Lastly: you now don't have your program spitting out grades. You used to do this in your invocationlist iteration but that was the wrong place for multiple reasons (abuse of events, single responsibility, etc).

I would suggest making a service that allows you to pass in a grade and have it spit out the output.



Combining all these remarks brings me to this:

public class Worker
{
   public event EventHandler Started;
   public event EventHandler Progressing;
   public event EventHandler Completed;

   public void DoWork()
   {
        Console.WriteLine("Worker: work started");
        if (Started != null)
        {
            Started(this, EventArgs.Empty);
        }

        Console.WriteLine("Worker: work progressing");
        if (Progressing != null)
        {
            Progressing(this, EventArgs.Empty);
        }

        Console.WriteLine("Worker: work completed");
        if(Completed != null)
        {
            Completed(this, EventArgs.Empty);
        }
   }
}

public class Boss
{
   public async void WorkCompleted(object sender, EventArgs e)
   {
       await Task.Delay(TimeSpan.FromSeconds(3));
       Console.WriteLine("Better...");
       Grader.Grade(5);
   }
}

public static class Grader
{
    public static void Grade(int grade)
    {
        Console.WriteLine("Worker grade = {0}", grade);
    }
}

public class Universe
{
   public void WorkerStartedWork(object sender, EventArgs e)
   {
       Console.WriteLine("Universe notices worker starting work");
   }

   public async void WorkerCompletedWork(object sender, EventArgs e)
   {
       await Task.Delay(TimeSpan.FromSeconds(10));
       Console.WriteLine("Universe pleased with worker's work");
       Grader.Grade(7);
   }

    private static void Main()
    {
        var universe = new Universe();
        var peter = new Worker();
        var boss = new Boss();
        peter.Completed += boss.WorkCompleted;
        peter.Started += universe.WorkerStartedWork;
        peter.Completed += universe.WorkerCompletedWork;
        peter.DoWork();

        Console.WriteLine("Main: worker completed work");
        Console.ReadLine();
    }
}




I toyed around with events as well some time ago so you might be interested in taking a look at my proof of concept: https://github.com/Vannevelj/VariousSmallProjects/tree/master/KeyConcepts/KeyConcepts/Events