委托可以更改委托链中的参数吗? (C#)

时间:2017-01-01 12:37:47

标签: c# events

我们有1个活动,2个订阅者。当事件上升第1个(功能)更改参数时,该参数为参考类型。第二个订户是否会更改参数或原点?

1 个答案:

答案 0 :(得分:10)

您不能将参数更改为具有不同的值,假设它是一个按值参数,但是(一如既往)您可以修改该值所引用的对象。

示例:

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);
    }
}

输出:

a
a
ay
ayz

换句话说:

  • 第一个操作会更改其参数的值;这不会影响其他任何事情
  • 第二个操作将“y”附加到其参数引用的StringBuilder对象
  • 第三个动作可以“看到”第二个动作所做的更改,并附加“z”
  • 调用代理后,调用者可以看到他们的更改

这与通过值传递参数的常规方法调用完全相同。

现在你可以声明委托使用ref参数 - 此时它的行为类似于带有ref参数的方法,并且更改参数本身 对链中的后来代表可见。以下是使用新RefAction<T>委托的上述示例的一个版本:

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);
    }
}

现在输出是:

a
x
xy
xyz

...这表明sb action1的价值变化在其他任何地方都可见。