what Delegates are doing?

VitzzViperzz

Well-known member
Joined
Jan 16, 2017
Messages
75
Location
United Kingdom
Programming Experience
1-3
So the book that I am following has now got me to using delegates in C#. However, there was a bit of code that baffled me a little.

C#:
delegate double processDelegate(double param1, double param2);
        static double Multiply(double param1, double param2) => param1 * param2;
        static double Divide(double param1, double param2) => param1 / param2;

so we start by declaring the delegates and creating variables into their parameters and then saying what they do.

C#:
int commaPos = input.IndexOf(',');
            double param1 = Convert.ToDouble(input.Substring(0, commaPos));
            double param2 = Convert.ToDouble(input.Substring(commaPos + 1, input.Length - commaPos - 1));

But this is what confused me! I don't quite understand what we are doing here.

What I can say is that we are converting param1 value to a double. I don't understand what the input, substring and the values in the parameters are doing. I think knowing what the 'commaPos' did would be useful - but can someone explain?

Thanks
 
The word "delegate" is actually used in two slightly different ways. First, a delegate can be a type, just as a class is a type. Like classes, delegates are reference types, i.e. a variable of that type contains a reference to an object rather than an object itself. Just as you create instances of classes, so you create instances of a delegates and those objects are also referred to as delegates. That means that a delegate object is an instance of a delegate type.

A delegate object is an object that contains a reference to a method. The idea is that you can create a delegate to a method and then pass that object around like you would any other object. You can then invoke the delegate to execute the method it refers to in places that would normally not have access to it because they aren't aware of the object that the method is a member of. For instance, the List<T> class has an overload of its Sort method that accepts a Comparison<T> delegate. The Comparison<T> delegate is defined as taking two objects of type T and returning an int that indicates their relative order. You can then write a method in a form that takes two objects of a particular type and returns an int that indicates their relative order, create a Comparison<T> delegate for that method and then pass it to the Sort method of a List<T>. That List is then able to invoke your method for the purposes of sorting, even though it doesn't know that your form exists.

Now let's look at your code. This first line:
delegate double processDelegate(double param1, double param2);

declares the delegate type. 'processDelegate' is now a type that can refer to any method that has two 'double' parameters and a return type of 'double'. The delegate type says nothing about how such methods should be implemented. The next two lines:
static double Multiply(double param1, double param2) => param1 * param2;
static double Divide(double param1, double param2) => param1 / param2;

declare two methods with signatures that match the 'processDelegate' type. That means that you can create instances of the 'processDelegate' type that refer to either of those methods. The first method multiplies the two parameters together and returns the result and the second method divides the first parameter by the second and returns the result. They could be written long-hand like this:
static double Multiply(double param1, double param2)
{
    return param1 * param2;
}

static double Divide(double param1, double param2)
{
    return param1 / param2;
}

The next three lines have exactly zero to do with delegates. They would simply be part of an example that shows how to use the delegate and methods above. This code:
int commaPos = input.IndexOf(',');
double param1 = Convert.ToDouble(input.Substring(0, commaPos));
double param2 = Convert.ToDouble(input.Substring(commaPos + 1, input.Length - commaPos - 1));

is simply extracting two doubles to use as arguments to the methods above. The input would be a single string that contains two numbers separated by a comma, e.g. "9.3,3.1". The code will then convert that to the double values 9.3 and 3.1, ready to be passed to 'processDelegate' instances that refer to your Multiply and Divide methods. The subsequent code would presumably do that, e.g.
var multiplier = new processDelegate(Multiply);
var divider = new processDelegate(Divide);

var product = multiplier(param1, param2);
var quotient = divider(param1, param2);

After that code, 'product' would contain 28.83 and quotient would contain 3.0. The code creates delegates that refer to the two methods and then invokes the delegates. Internally the delegate will call the method it refers to, passing in its own parameters as argument. That code is basically equivalent to this:
var product = Multiply(param1, param2);
var quotient = Divide(param1, param2);

It has no specific advantage over that in this particular case but, as I said, you could, if you wanted to, pass those delegates around and then invoke them somewhere that has no direct access to the Multiply and Divide methods.

A note on naming delegates now. Microsoft recommends that delegates NOT be suffixed with 'Delegate'. You'll find that throughout the .NET Framework, e.g. Comparison<T>, Action, Func, etc, etc. If everyone can use those types successfully without a suffix, you can live without a suffix on your own delegates. Also, EVERY type name should begin with an upper-case letter. That means that Process would be a better name than 'processDelegate'.

Also, unless it's use implies something specific, there's no point to declaring your own delegate types. For instance, the Comparison<T> delegate DOES imply something specific, i.e. the two arguments are to be compared and the result is to indicate their relative order. In most cases, you should just use an Action or a Func. Action delegates can have up to 16 parameters of any type and do not return anything while Func delegates can also have 16 parameters and do return something. In your case above, you could have used a Func<double, double, double>, although doing so would not have taught you how to declare delegate types.
 
I saw your answer this morning and I wanted to wait until I could really sit down and absorb the information that you were sharing. I have mad lots of notes in the IDE next to the code and I can look back at them.

You have a flair in teaching. The points that you were making were all very easily understood and they followed each other very well.

Thank you for your very detailed answer - I appreciate you taking the time to write a reply as good as this.

:adoration:
 
Last edited:
Back
Top Bottom