С# делегат не работает так, как должен?

im kinda new для С#, поэтому я придумал эту проблему. Вопрос: почему func2 называется? Да, и еще одна вещь. Я добавляю функцию к делегату. В этой функции я вызываю другого делегата, однако я хочу удостовериться, что каждая другая функция, добавленная к первому делегату, вызывается до того, как эта функция вызовет этот делегат, есть ли какое-то чистое решение (не очень заинтересованное getInvocationList). Спасибо, ребята, ты лучший.

class Program
{
    delegate void voidEvent();
    voidEvent test;

    private void func1()
    {
        Console.Write("func1");
        test -= func2;
    }

    private void func2()
    {
        Console.WriteLine("func2");
    }

    static void Main(string[] args)
    {
        Program p = new Program();
        p.test += p.func1;
        p.test += p.func2;
        p.test();
    }
}

Ответ 1

Каждый раз, когда вы меняете делегата (+ = или - =), вы фактически создаете целую копию списка вызовов (методы, которые будут вызваны).

Из-за этого, когда вы вызываете p.test();, вы будете вызывать каждый делегат в списке вызовов в этот момент времени. Изменение этого внутри одного из этих обработчиков изменит его для следующего вызова, но не изменит текущий исполняемый вызов.

Ответ 2

Рид, конечно, правильный. Вот еще один способ подумать об этом.
class Number
{
    public static Number test;
    private int x;
    public Number(int x) { this.x = x; }
    public Number AddOne() 
    {
        return new Number(x + 1);
    }
    public void DoIt()
    {
        Console.WriteLine(x);
        test = test.AddOne();
        Console.WriteLine(x);
    }
    public static void Main()
    {
        test = new Number(1);
        test.DoIt(); 
    }
}

Должна ли печать 1, 1 или 1, 2? Почему?

Он должен печатать 1, 1. Когда вы говорите

test.DoIt();

что не означает

        Console.WriteLine(test.x);
        test = test.AddOne();
        Console.WriteLine(test.x);

! Скорее, это означает

Number temporary = test;
Console.WriteLine(temporary.x);
test = test.AddOne();
Console.WriteLine(temporary.x);

Изменение значения test не меняет значение this в DoIt.

Вы делаете то же самое. Изменение значения test не изменяет список функций, которые вы вызываете; вы попросили указать конкретный список функций, которые будут вызываться, и этот список будет вызван. Вы не можете изменить его на полпути, больше, чем вы можете изменить значение this на полпути вызова метода.