C# delegate only writes out last method
Asked Answered
H

5

5

I have this code:

public void myMethod()
{
    int a = 10;
    int b = 20;
    Func<int, int, int> multiplyDelegate;
    multiplyDelegate = Multiply;
    multiplyDelegate += Multiply2;

    Console.WriteLine(multiplyDelegate(a,b));
}

public int Multiply(int x, int y)
{
    return x * y;
}
public int Multiply2(int x, int y)
{
    return x * y + 10;
}

By running myMethod, I expect the console to show the returns from both methods "Multiply" and "Multiply2" but only the return from the method "Multiply2" is shown. Have I done something wrong here or have I misunderstood the concept of delegates? From what I've learned a delegate is an array of references to methods.

Hardecanute answered 25/4, 2017 at 12:19 Comment(1)
it calls both but it does not write bothAshla
P
6

You are right delegate can store methods and invoke multiple methods at once. It will return the last one except if you explicitly Invoke them.

Using your code, here is an example of explicite Invoke for all of your collection of methods.

var results = multiplyDelegate.GetInvocationList().Select(x => (int)x.DynamicInvoke(10, 20));
foreach (var result in results)
    Console.WriteLine(result);

EDIT :

This will work for function Func and not Action. Here is an example supposing it's an Action

foreach (Delegate action in multiplyDelegate.GetInvocationList())
{
    action.DynamicInvoke(10, 20);
    // Do Something
}

This second example work for Func as well.

Philippeville answered 25/4, 2017 at 12:31 Comment(1)
Thanks Lostblue, that made it :)Hardecanute
W
12

From Using Delegates (C# Programming Guide):

If the delegate has a return value and/or out parameters, it returns the return value and parameters of the last method invoked.

Wilkinson answered 25/4, 2017 at 12:24 Comment(0)
P
6

You are right delegate can store methods and invoke multiple methods at once. It will return the last one except if you explicitly Invoke them.

Using your code, here is an example of explicite Invoke for all of your collection of methods.

var results = multiplyDelegate.GetInvocationList().Select(x => (int)x.DynamicInvoke(10, 20));
foreach (var result in results)
    Console.WriteLine(result);

EDIT :

This will work for function Func and not Action. Here is an example supposing it's an Action

foreach (Delegate action in multiplyDelegate.GetInvocationList())
{
    action.DynamicInvoke(10, 20);
    // Do Something
}

This second example work for Func as well.

Philippeville answered 25/4, 2017 at 12:31 Comment(1)
Thanks Lostblue, that made it :)Hardecanute
V
1

I don't have any official sources for this, but I think what is happening is that you can't return two values from one delegate call. Therefore, the last value returned is used.

Although only the last return value is used, the two methods are indeed executed. We can prove this by printing some stuff before we return:

public int Multiply(int x, int y)
{
    Console.WriteLine("Hello1");
    return x * y;
}
public int Multiply2(int x, int y)
{
    Console.WriteLine("Hello2");
    return x * y + 10;
}

Both Hello1 and Hello2 are printed.

Varsity answered 25/4, 2017 at 12:25 Comment(3)
I copied your code into my document and only Hello2 and 190 is shown in my console.Hardecanute
@RobinCox I tried it on csharppad.com and it shows both Hello1 and Hello2. Maybe this is a new behaviour of C# 6 and you are using C# 5? See this; csharppad.com/gist/d0a0c42badee28aa3e908376cd6e7fb5Varsity
That's strange since I have Visual Studio 2017Hardecanute
P
0

Only one object can be returned and since Multiple2 is the last to execute it get's outputted in the console.

There isnt a way to change that.

You could do:

public void myMethod()
        {
            int a = 10;
            int b = 20;
            Action<int, int> multiplyDelegate;
            multiplyDelegate = Multiply;
            multiplyDelegate += Multiply2;
            multiplyDelegate(10, 20);

            Console.Read(); 
        }

        public void Multiply(int x, int y)
        {
            Console.WriteLine(x * 2);
        }
        public void Multiply2(int x, int y)
        {
            Console.WriteLine(x * y + 10);
        }
Purificator answered 25/4, 2017 at 12:24 Comment(0)
G
-1

I had this question too and test several things like another way of setting method to the delegate but finally only usable way is to write another line after each set:

public void myMethod()
{
    int a = 10;
    int b = 20;
    Func<int, int, int> multiplyDelegate;
    multiplyDelegate = Multiply;
    Console.WriteLine(multiplyDelegate(a,b));

    multiplyDelegate += Multiply2;

    Console.WriteLine(multiplyDelegate(a,b));
}

public int Multiply(int x, int y)
{
    return x * y;
}
public int Multiply2(int x, int y)
{
    return x * y + 10;
}
Gaither answered 5/9, 2021 at 18:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.