Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can delegates change parameters in delegate chain? (C#)

Tags:

c#

events

We have 1 event, 2 subscribers. When event rises 1st subsriber (function) change parameter and this parameter is of reference type. Will the second subscriber get changed parameter or the origin one?

like image 698
Dragonborn Avatar asked Oct 17 '25 02:10

Dragonborn


1 Answers

You can't change the parameter to have a different value assuming it's a by-value parameter, but (as always) you may be able to modify the object that the value refers to.

Example:

using System;
using System.Text;

class Test
{
    static void Main(string[] args)
    {
        Action<StringBuilder> action1 = sb =>
        {
            Console.WriteLine(sb);
            sb = new StringBuilder("x");
        };
        Action<StringBuilder> action2 = sb =>
        {
            Console.WriteLine(sb);
            sb.Append("y");
        };
        Action<StringBuilder> action3 = sb =>
        {
            Console.WriteLine(sb);
            sb.Append("z");
        };

        Action<StringBuilder> all = action1 + action2 + action3;
        StringBuilder builder = new StringBuilder("a");
        all(builder);
        Console.WriteLine(builder);
    }
}

Output:

a
a
ay
ayz

In other words:

  • The first action changes the value of its parameter; this doesn't affect anything else
  • The second action appends "y" to the StringBuilder object its parameter refers to
  • The third action can "see" the change made by the second action, and it appends "z"
  • After the delegates have been invoked, their changes are visible to the caller

This is all exactly the same as regular method calls passing the parameter by value.

Now you can declare a delegate to use ref parameters - at which point it behaves like a method with a ref parameter, and changes to the parameter itself are visible to later delegates in the chain. Here's a version of the above example using a new RefAction<T> delegate:

using System;
using System.Text;

delegate void RefAction<T>(ref T arg);

class Test
{
    static void Main(string[] args)
    {
        RefAction<StringBuilder> action1 = (ref StringBuilder sb) =>
        {
            Console.WriteLine(sb);
            sb = new StringBuilder("x");
        };
        RefAction<StringBuilder> action2 = (ref StringBuilder sb) =>
        {
            Console.WriteLine(sb);
            sb.Append("y");
        };
        RefAction<StringBuilder> action3 = (ref StringBuilder sb) =>
        {
            Console.WriteLine(sb);
            sb.Append("z");
        };

        RefAction<StringBuilder> all = action1 + action2 + action3;
        StringBuilder builder = new StringBuilder("a");
        all(ref builder);
        Console.WriteLine(builder);
    }
}

Now the output is:

a
x
xy
xyz

... which shows that the change to the value of sb in action1 is visible everywhere else.

like image 120
Jon Skeet Avatar answered Oct 18 '25 15:10

Jon Skeet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!