Author Topic: Event Delegate Bug  (Read 3551 times)

AtomicBob

  • Jr. Member
  • **
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 69
    • View Profile
Event Delegate Bug
« on: July 25, 2014, 12:31:21 PM »
I have a method Show ( Action onHide = null ) that I call using a UIButton's OnClick delegate. I don't specify any parameter and let the Event Delegate pass null. This works in the first scene that's loaded, but not in subsequent scenes. It looks to be a bug/side-effect of the serialize-deserialize process Unity goes through when changing scenes. The mParameters array has a single element in my case with a value of null and a type of void. The serialization process ends up converting the null element to UnityEngine.Object instead of void. This causes the next invocation to throw an InvalidParameterException.

Reproduction should be very straightforward:
1) Assign a UIButton's OnClick to a method that takes a reference type parameter that doesn't derive from UnityEngine.Object
2) Play a scene and call DontDestroyOnLoad on the button's GameObject
3) Click the button in your first scene (so the EventDelegate caches stuff)
4) Move to another scene
5) Click the button again in the new scene
6) Exception

AtomicBob

  • Jr. Member
  • **
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 69
    • View Profile
Re: Event Delegate Bug
« Reply #1 on: July 25, 2014, 01:52:03 PM »
I changed EventDelegate.cs:75 from

  1. return obj;
  2.  

to

  1. if ( obj != null ) return obj;
  2. if ( expectedType.IsValueType ) return null;
  3. return System.Convert.ChangeType(null, expectedType);
  4.  

as a quick hack around. I'm not sure if it covers all cases, but it covers mine for the time being.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Event Delegate Bug
« Reply #2 on: July 26, 2014, 03:31:46 AM »
I'm not sure I follow you here... 'EventDelegate.Parameter.obj' is of type 'UnityEngine.Object', and you say you want it to not be derived from that... Unity isn't able to serialize anything that doesn't derive from UnityEngine.Object, which is why it's that, and not System.Object. If your step 1 used something that does derive from UnityEngine.Object, then your post would make more sense to me. Can you clarify?

AtomicBob

  • Jr. Member
  • **
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 69
    • View Profile
Re: Event Delegate Bug
« Reply #3 on: July 30, 2014, 01:23:14 PM »
Yea, this one is a bit tricky to explain clearly. What it boils down to is that EventDelegate doesn't support default parameters or intentionally passing null.

I'll do my best to explain fully. There are 2 cases. 1:

You have a method that takes a parameter that is a reference type deriving from System.object. e.g.
  1. public void DoSomething ( Action onFinished )
You want to call this method with an EventDelegate on a UIButton.
You want to pass null for onFinished
You assign the relevant object to the EventDelegate.
You want to pass null so you don't specify the Arg0 target.
An exception will occur because the parameter that actually get's used will be either
  1. (System.void) null
or
  1. (UnityEngine.Object) null
instead of
  1. (System.Action) null
.

Supporting this would mean doing something like I posted above. At the end of EventDelegate.Parameter.value:

  1. if ( !expectedType.IsValueType ) return System.Convert.ChangeType(null, expectedType);
  2. return obj;
  3.  

2:

You have a method that has a default value for the parameter. e.g.
  1. public void DoSomething ( int index = 0 )
You want to call this method with an EventDelegate on a UIButton.
You want to not pass the int and let it use the default value.
You assign the relevant object to the EventDelegate.
You don't want to specify the argument, so you don't specify the Arg0 target.
An exception will occur.

I think to support this you'd have to do a little more reflection to see if the method has default parameters and if it does, invoke the method in a slightly different way. http://stackoverflow.com/questions/2421994/invoking-methods-with-optional-parameters-through-reflection

These can be worked around with an overload for the method, but I wanted to point them out in case you want to support the scenarios. The first one seems very straight forward, though the second one may or may not be worth the effort.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Event Delegate Bug
« Reply #4 on: July 31, 2014, 10:49:22 AM »
As I recall something in Unity doesn't support default parameters... MonoDevelop? I'm not sure, I don't use it, but I vaguely remember that being the reason for me having to write out all the overloads in NGUI.

AtomicBob

  • Jr. Member
  • **
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 69
    • View Profile
Re: Event Delegate Bug
« Reply #5 on: July 31, 2014, 10:52:49 AM »
Hmm. The only thing I've ever heard of was an issue with methods with default parameters inside a namespace. That used to cause Unity to choke and not allow you to add the script to a GameObject. That was fixed in 4.5. I use default parameters fairly often (usually for callbacks) and haven't run into any issues personally, but I don't use MonoDevelop.