多播委托始终执行最后一次操作

时间:2011-08-03 11:30:08

标签: c# delegates

所以我有以下代码:

namespace ConsoleApplication1
{
    public delegate int Transformer(int x);

    class Test
    {
        public static void Transform(int[] values, Transformer t)
        {
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = t(values[i]);
            }
        }

       static int Square(int x)
        {
            return x * x;
        }

        static int Minus(int x)
       {
           return x - 1;
       }

        static void Main()
        {
            int[] values = { 1, 2, 3 };
            Transformer t = Test.Minus;
            t += Test.Square;

            Test.Transform(values, t);

            foreach (int i in values)
            {
                Console.Write(i + " ");
            }
        }
    }
}

为什么它总是只对数组进行最后一次操作(在我的情况下为Square)。我需要改变什么才能做到Minus和Square?

2 个答案:

答案 0 :(得分:4)

多播代理始终返回链中最后一个委托的值。由于您不修改Test.Minus和Test.Square中的值,但返回新值,因此仅应用后者。解决此问题的最简单方法是使变换器通过引用获取值并进行修改。 e.g:


namespace ConsoleApplication1
{
    public delegate void Transformer(ref int x);

    class Test
    {
        public static void Transform(int[] values, Transformer t)
        {
            for (int i = 0; i < values.Length; i++)
            {
                t(ref values[i]);
            }
        }

       static void Square(ref int x)
       {
           x = x * x;
       }

       static void Minus(ref int x)
       {
           x = x - 1;
       }

        static void Main()
        {
            int[] values = { 1, 2, 3 };
            Transformer t = Test.Minus;
            t += Test.Square;

            Test.Transform(values, t);

            foreach (int i in values)
            {
                Console.Write(i + " ");
            }
        }
    }
}

答案 1 :(得分:3)

因为结果没有通过所有代理链接

代码相当于

 Minus(1);
 return Square(1);

更改代码以更改变量。

 public delegate void Transformer(ref int x);

    public static void Transform(int[] values, Transformer t)
    {
        for (int i = 0; i < values.Length; i++)
        {
            t(ref values[i]);
        }
    }

   static void Square(ref int x)
    {
        x*= x;
    }

    static void Minus(ref int x)
   {
       x--;
   }

更好的解决方案是使用linq agregate,因为您可以在不影响源的情况下转换解决方案。

public static int[] Transform(int[] values, params Func<int,int>[] t){
  return values.Select(v=>t.Aggregate(v,(x,f)=>f(x))).ToArray();
}

然后你可以打电话

values=Transform(values,new[] { Minus,Square });

int[] values = {1,2,3};
int[] result = Transform(values,Minus,Square);

此调用值后!=结果因此源未更改