Generic delegate in C# 3.0 or .NET 3.5

As we do event-based programming or implement publish-subscribe pattern, we use the delegate feature from .NET heavily. The sample code below demonstrates simple usage of the feature.

    public delegate void DataChangedDelegate(int oldValue, int newValue);

    class Foo

    {

        public DataChangedDelegate OnDataChanged = null;

        private int _data = 0;

        public int Data

        {

            get { return _data; }

            set { UpdateData(value); }

        }

        private void UpdateData(int updatedData)

        {

            if (OnDataChanged != null)

            {

                OnDataChanged(_data, updatedData);

            }

            _data = updatedData;

        }

    }

We can then create an instance of Foo class, and hook up the event handler to its public delegate as shown below.

     class Program

    {

        static void Main(string[] args)

        {

            Foo foo = new Foo();

            foo.OnDataChanged += OnDataChanged;

            foo.Data = 2;

            Console.WriteLine();

        }

        static void OnDataChanged(int oldValue, int newValue)

        {

            Console.WriteLine("Data changes from " + oldValue + " to " + newValue);

        }

    }

 

C# 3.0 or .NET 3.5 has new feature that provides us a set of generic delegates with the name "Action" or "Func", the difference between them is Action does not have return type (void), while Func has return type (refer to MSDN documentation). So from example above we can remove following code:

    public delegate void DataChangedDelegate(int oldValue, int newValue);

and replace following code: 

        public DataChangedDelegate OnDataChanged = null;

with:

        public Action<int, int> OnDataChanged = null; 

If the delegate returns bool data type for example, then we can use Func function such as:

        public Func<int, int, bool> OnDataChanged = null;

 

Although this new feature allows us not to declare the delegate types (means less line of code), but we may use our judgement whether to use it or not. The reason is because sometimes we may prefer to name the delegate type to make us better understand the code. Another thing is we can't use the delegate type we created interchangeably with its counterpart generic delegates unfortunately even though they have same signature (and not with explicit conversion either). For example, the following code below will not work.

            DataChangedDelegate dataChanged;

            Action<int, int> genericFunc;

            dataChanged = genericFunc; // compile error