Search Unity

Removing methods C# delegates

Discussion in 'Scripting' started by HeywoodFloyd, Sep 11, 2009.

  1. HeywoodFloyd

    HeywoodFloyd

    Joined:
    May 27, 2009
    Posts:
    16
    Howdy,

    I've been trying to use C# delegates and running into some problems. I can declare a delegate and add methods to it, but removing methods never seems to work. For example, I have code similar to:

    Code (csharp):
    1. delegate void SomeAction(string p1, object p2);
    2.  
    3. void printFoo(string p1, object p2)
    4. {
    5.   Debug.Log("foo");
    6. }
    7.  
    8. ...
    9.  
    10. SomeAction myActions = printFoo;
    11. myActions -= printFoo;

    which should result in myActions not doing anything when called, but I still see the printFoo method executed.

    I've looked through the forums quite a bit, but I couldn't find anybody every removing a method from a delegate.

    TIA
     
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    The -= operator doesn't delete things, it decrements a numeric value by a specified amount:-
    Code (csharp):
    1. x -= 3;   // Decrement x by 3
    You can set a delegate variable to null to mark it as uncallable, but if you attempt to call the null delegate, you will get an error. If you want a delegate that does nothing when called, just declare an empty function that matches the delegate parameter template.
     
  3. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
  4. MaxMakhotkin

    MaxMakhotkin

    Joined:
    Sep 11, 2009
    Posts:
    16
    These delegates are a kind of pointer to a function. You cannot just add or remove anything from it, but yes, you can use them to pass as parameters to other functions.
     
  5. NCarter

    NCarter

    Joined:
    Sep 3, 2005
    Posts:
    686
    This works for me:

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class MulticastDelegateTest : MonoBehaviour
    5. {
    6.     delegate void Something();
    7.  
    8.     void SomeMethod()
    9.     {
    10.         Debug.Log("SomeMethod");
    11.     }
    12.  
    13.     void AnotherMethod()
    14.     {
    15.         Debug.Log("AnotherMethod");
    16.     }
    17.  
    18.     void Start()
    19.     {
    20.         Something something = SomeMethod;
    21.         something += AnotherMethod;
    22.  
    23.         Debug.Log("Calling both methods:");
    24.  
    25.         something();
    26.  
    27.         something -= SomeMethod;
    28.  
    29.         Debug.Log("Calling just one method:");
    30.  
    31.         something();
    32.     }
    33. }
    It's also possible to subtract the only remaining method, at which point you get a null reference exception if you try to call it, so I think your code should work. I'm guessing that the problem is actually a logic error elsewhere in your code.
     
  6. HeywoodFloyd

    HeywoodFloyd

    Joined:
    May 27, 2009
    Posts:
    16
    Thanks for the replies.

    I think the problem may be that one of the methods called via the delegate tried to remove itself from the delegate. While this doesn't throw an exception or anything, it apparently doesn't work.

    It makes sense that this wouldn't be allowed, as whatever the delegate is using to enumerate through its methods being called would be messed up. It'd be nice if it through an exception, though.
     
  7. HeywoodFloyd

    HeywoodFloyd

    Joined:
    May 27, 2009
    Posts:
    16
    I fixed the problem with a method removing itself from its delegate, ensuring that removal of delegates and executing them happened at different times. I *still* didn't see the methods being removed from the delegates, so there was still some weirdness.

    I worked around it by saving delegates in list, one method per delegate, rather than adding methods to a single delegate. This gave the desired behavior, but I'm still at a loss as to why I had to do it.
     
  8. thedmd

    thedmd

    Guest

    How about events?

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class MulticastDelegateTest : MonoBehaviour
    5. {
    6.   private delegate void SomethingDelegate();
    7.  
    8.   private event SomethingDelegate Something;
    9.  
    10.   private void SomeMethod()
    11.   {
    12.     Debug.Log("SomeMethod");
    13.   }
    14.  
    15.   private void AnotherMethod()
    16.   {
    17.     Debug.Log("AnotherMethod");
    18.   }
    19.  
    20.   private void InvokeSomething()
    21.   {
    22.     if (Something != null)
    23.       Something();
    24.   }
    25.  
    26.   public void Start()
    27.   {    
    28.     Debug.Log("Calling none methods:");
    29.  
    30.     InvokeSomething();
    31.  
    32.     Something += new SomethingDelegate(SomeMethod);
    33.     Something += new SomethingDelegate(AnotherMethod);
    34.  
    35.     Debug.Log("Calling both methods:");
    36.  
    37.     InvokeSomething();
    38.  
    39.     Something -= new SomethingDelegate(SomeMethod);
    40.  
    41.     Debug.Log("Calling just one method:");
    42.  
    43.     InvokeSomething();
    44.   }
    45. }
    Above code works for me. Adding and removing also works. Invoke method was introduced becouse event is nulled when no any handlers are assigned.
     
  9. HeywoodFloyd

    HeywoodFloyd

    Joined:
    May 27, 2009
    Posts:
    16
    Thanks.

    One thing I've noticed with my delegate system is that it's having trouble finding methods from Javascript scripts. Javascript methods get added to delegates (in C# classes) with no problem, but they don't get removed. This is true whether I'm using my List<> work-around or not.

    I haven't tried the event trick yet. I'll give it a go.
     
  10. HeywoodFloyd

    HeywoodFloyd

    Joined:
    May 27, 2009
    Posts:
    16
    Tried storing my functions in events, rather than delegates. Still can't remove Javascript functions.
     
  11. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Having hurriedly tried to fill that gap in my knowledge :oops: I've had a thought about this... is it possible that your code is somehow adding the same delegate method more than once? The Delegate class has a method called GetInvocationList that returns an array of all the individual delegate methods contained within the "master" delegate. If you get the length of this array after combining the delegate methods, you should be able to check if the length of this array is what it should be. I don't know why a problem like this would happen - it might indicate a bug somewhere, maybe with the JS compiler.
     
  12. HeywoodFloyd

    HeywoodFloyd

    Joined:
    May 27, 2009
    Posts:
    16
    Thanks! I didn't know about GetInvocationList, which does sound useful.

    I didn't use that, but I did put Debug.Log messages in my methods that add functions to the events/delegates, and counted them up. I didn't see any extra calls to the adds.

    I'm beginning to suspect that JS methods don't look like C# methods to whatever mechanism searches for them. I didn't see the JS methods match when I stored methods as delegates, as delegates inside of Lists, or in Events. It's either a bug in the compiler or some blinding bias that I have that's keeping me from seeing the errors in my script. (I'm hoping for the former, as it's probably easier to fix.)
     
  13. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    It might be a good idea to check the length of the invocation list after all the delegates have been added. I'm thinking there might be a more subtle bug (perhaps internal to Unity/Mono) that is causing the problem and there may be a workaround.
     
  14. Nick-Wiggill

    Nick-Wiggill

    Joined:
    Jan 31, 2010
    Posts:
    46
    @thedmd

    Thank you. That's all I wanted to see for the last 2 hours searching these forums and UnifyCommunity. The clean, correct native C# method of dispatching multicast events, for someone new to the C# event paradigm.
     
  15. flamy

    flamy

    Joined:
    Feb 7, 2011
    Posts:
    194
    really useful post thanks for everyone who replied