从链中删除委托

Gri*_*uev 5 .net c# clr

class Program
{
    internal delegate int CallBack(int i);

    static void Main(string[] args)
    {
        CallBack callbackMethodsChain = null;
        CallBack cbM1 = new CallBack(FirstMethod);
        CallBack cbM2 = new CallBack(SecondMethod);

        callbackMethodsChain += cbM1;
        callbackMethodsChain += cbM2;

        Delegate.Remove(callbackMethodsChain, cbM1);
    /*L_0039: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class  [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
        L_003e: pop 
        L_003f: ldloc.0 */

        Trace.WriteLine(callbackMethodsChain.GetInvocationList().Length);
        //Output: 2 **WTF!!!**


        callbackMethodsChain -= cbM1;
        /*
    L_0054: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class   [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
          L_0059: castclass Generics.Program/CallBack
          L_005e: stloc.0 
          L_005f: ldloc.0 
        */
        Trace.WriteLine(callbackMethodsChain.GetInvocationList().Length);
        //Output: 1
    }

    private static int FirstMethod(int test)
    {            
        Trace.WriteLine("FirstMethod");
        return test;
    }

    private static int SecondMethod(int test)
    {
        Trace.WriteLine("SecondMethod");
        return test;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,我们总是需要强制转换(CallBack)Delegate.Remove(callbackMethodsChain,cbM1); 从链中删除委托.这显然不是.

ang*_*son 12

委托是不可变的,这意味着您无法更改它.任何似乎改变它的方法,比如"添加"它或"从中减去",实际上会返回一个包含更改的新委托.

所以这不起作用:

a.Remove(b);
Run Code Online (Sandbox Code Playgroud)

但这会:

a = a.Remove(b);
Run Code Online (Sandbox Code Playgroud)

在调用Remove方法方面.

请注意,以下语法正确的做法:

a -= b;
Run Code Online (Sandbox Code Playgroud)

这就是为什么在调用Remove之后,你仍然会观察到调用你看似被删除的委托的代码,你仍然会调用原来的委托链.