C# Delegates General


This entry is part 5 of 8 in the series C# Delegates

A General Case

In this post we are going to take the Photo Processor example and change the names to more general names so that we can better apply Delegates to our own code by taking this general case and changing the code to suit our objects. For example, in this code we have called our class MyClass and given it two properties and a method. Here, we won’t use the method but we will use the two properties.

This program has the following four files:

  • MyClass
  • MyClassMethods
  • MyClassProcessor
  • Program

We have a project called DelegatesGeneral. Below is the class. For your project all you have to do is change the name of MyClass and the names of the properties and methods in this code to suit your project. Add more properties and methods as needed.

MyClass

namespace DelegatesGeneral
{
    class MyClass
    {
        public string MyString { get; set; }
        public int MyInt { get; set; }
        public static MyClass MyClassDoMethod()
        {   
            return new MyClass();  // we don't use this
        }
    }
}

Library Methods

We’ve written a few methods that take in our class and perform something on it by changing one property. The class is called MyClassMethods. Your code could do whatever you needed it to do.

using System;
namespace DelegatesGeneral
{
    class MyClassMethods
    {
        // Library
        //
        // this is like a library of methods we have that operate on
        // our class called MyClass.
        // the consumer of our software (Main) can write their own library
        // and use those methods with our software, making our 
        // software extensible and flexible, similar to a Framework.
        public void AddOne(MyClass mc)
        {  // here we do something with the object mc
            mc.MyInt = mc.MyInt + 1;
            Console.WriteLine("AddOne: " + mc.MyString + " " + mc.MyInt);
        }
        public void DoubleIt(MyClass mc)
        {
            mc.MyInt = mc.MyInt * 2;
            Console.WriteLine("DoubleIt: " + mc.MyString + " " + mc.MyInt);
        }
        public void AppendString(MyClass mc)
        {
            mc.MyString = mc.MyString + " appending this string now ";
            Console.WriteLine("AppendString: " + mc.MyString + " " + mc.MyInt);
        }
    }
}

MyClassProcessor

using System;
namespace DelegatesGeneral
{
    class MyClassProcessor
    {
        public int MyAmount { get; set; }

        public void Process(Action<MyClass> methodHandler)
        {   // methodHandler is a delegate 
            // instantiate it and use object initialization syntax
            // to set the two properties
            var myclass = new MyClass { MyString = "inside Process method ", MyInt = 1 };
            methodHandler(myclass);
            // we do not define the methods we want to run here because
            // we are going to let the consumer define that.
        }
    }
}

Program

using System;
namespace DelegatesGeneral
{
    class Program
    {
        static void Main(string[] args)
        {
            // Main is the consumer
            var myclassprocessor = new MyClassProcessor();
            var myclassmethods = new MyClassMethods();

            Action<MyClass> methodHandler = myclassmethods.AddOne;
            // methodHandler is a pointer to a group of functions (delegate)
            methodHandler += myclassmethods.DoubleIt;
            methodHandler += FromConsumerMinusOne;  // Here is the whole point of this! Extensible!
            methodHandler += myclassmethods.AppendString;

            Console.WriteLine("Generic Delegate Action:");
            myclassprocessor.Process(methodHandler);  // Process() takes a delegate
        }
        static void FromConsumerMinusOne(MyClass myC)
        {
            myC.MyInt = myC.MyInt - 1;
            Console.WriteLine("FromConsumerMinusOne: " + myC.MyString + myC.MyInt);
        }
    }
}

Instantiate the Class in Program

Alternatively we could instantiate our class in the main program and pass it to the Process method, instead of instantiating it in the Process method. How would that look?

using System;
namespace DelegatesGeneral
{
    class Program
    {
        static void Main(string[] args)
        {
            // Main is the consumer
            var myclassprocessor = new MyClassProcessor();
            var myclassmethods = new MyClassMethods();

            Action<MyClass> methodHandler = myclassmethods.AddOne;
            // methodHandler is a pointer to a group of functions (delegate)
            methodHandler += myclassmethods.DoubleIt;
            methodHandler += FromConsumerMinusOne;  // Here is the whole point of this! Extensible!
            methodHandler += myclassmethods.AppendString;

            Console.WriteLine("Generic Delegate Action:");
            // instantiate the class here (line below)
            var myclass = new MyClass { MyString = "inside Main() ", MyInt = 10 };
            myclassprocessor.Process(methodHandler, myclass);  // Process() takes a delegate
        }
        static void FromConsumerMinusOne(MyClass myC)
        {
            myC.MyInt = myC.MyInt - 1;
            Console.WriteLine("FromConsumerMinusOne: " + myC.MyString + myC.MyInt);
        }
    }
}

using System;
namespace DelegatesGeneral
{
    class MyClassProcessor
    {
        public int MyAmount { get; set; }

        public void Process(Action<MyClass> methodHandler, MyClass myclass)
        {   // methodHandler is a delegate 
            // instantiate MyClass and use object initialization syntax
            // to set the two properties
            //var myclass = new MyClass { MyString = "inside Process method ", MyInt = 1 };
            methodHandler(myclass);
            // we do not define the methods we want to run here because
            // we are going to let the consumer define that.
        }
    }
}

Series Navigation<< C# Delegates Part 4C# Delegates Steps >>