Многоадресный делегат всегда выполняет последнюю операцию - PullRequest
2 голосов
/ 03 августа 2011

Итак, у меня есть следующий код:

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).Что мне нужно изменить, чтобы оно работало как с минусом, так и с квадратом?

Ответы [ 2 ]

4 голосов
/ 03 августа 2011

Многоадресные делегаты всегда возвращают значение последнего делегата в цепочке. Поскольку вы не изменяете значения в Test.Minus и Test.Square, но возвращаете новые значения, применяется только последнее. Самый простой способ исправить это - заставить ваши трансформаторы принимать значения по ссылке и изменять их. например:


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

3 голосов
/ 03 августа 2011

Поскольку результат не объединен во всех делегатах

код становится эквивалентом

 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, поскольку вы можете преобразовать решение, не затрагивая источник.

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

После этого вызова значения! = Результат, поэтому источник не меняется

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...