✅ Class instance reference
I'm having some issues figuring out why my code is behaving like it's taking a "snapshot" of an instance instead of directly referencing it.
So I created a custom attribute so that I could check a class for methods with it and add the methods to the list. I had to "register" my methods after creating the instance so that they could access the instance members, and so in the class constructor I added:
For context, this is how a listener looks:
In my
MessageHandler
class I have this dictionary:
36 Replies
This is the registration code:
Finally, when I call the stored listener:
The listener gets called and the correct payload is passed and everything, but it seems like it can't access the instance members (in this case the
UdpConnection
class instance members).
If Instead of registering the handler in the constructor I call it later, the class members from that moment will be accessible when the listener is called. Is there a way to fix this so that the instance is stored as a reference and not this "snapshot" behavior here?I read this multiple times and don't quite understand what you are saying the problem is.
Is UdpConnection a struct?
What do you mean by can't access instance members? In the handler callback?
No so, the TL,DR is:
I have a class with a method that has the
[MessageListener]
attribute.
I then Register (Store) the methods that have this attribute on a dictionary to be called when an event happens.
When this even fires, the methods ARE called, but for some reason they "exist" in another class instance, it's like when I store the created delegate, even if I'm passing the instance it creates a new one.
Example flow:
- Instanciate class
- Set class member foo = "bar"
- Register listener
- Set class member foo = "changed"
- Event gets called
- Listener gets triggered
- In the listener, if I access the class member foo
the value will be bar
instead of changed
.
You can see however, that in the RegisterListeners function I am not creating a new instance at any point, so I don't understand why this is happening. Am I just not using the Delegate.CreateDelegate(delegateType, instance, method);
correctly? As u can see I am passing it the instance of the class, so when I call the created delegate it should exist in the same instance no?What are you expecting to happen?
UdpConnection is a class right not struct?
For the listner to exist in the same instance, so that even if values are changed after registering it, it will reside in the instance scope and so have access to them. In the example above, I'd expect
foo
to be changed
when accesing it though the listener
YepWhat you are describing only makes sense if it's a struct.
Unless I'm missing something.
There is no "snapshot" behavior for reference types.
Nope, it does not make sense, that's why I'm here haha
I've been battling this all day And I can see, through debugger that
this
when executing the listener does not have the updated membersThen the reference you are using is to change the value of the member must be pointing to a different instance.
I would double check your test code, you might be doing something wrong in there instead
Could you have an unexptected closure?
I'm not even testing yet, I was just writing it, I don't like TDD
Variable capture in a closure could be an issue, yeah.
But how do you know there's even an issue if you didn't test it??
that would be snapshot-ish
the Udpconnection class does inherit from IDisposable, but I did check and the instance is not disposed if that's what you are refering to
no
Run the code -> Code don't work xdd
That's what i meant by test
a closure captures scope, if it's intended that's great, if it's not...
Put a breakpoint on the UdpConnection constructor and see if another instance is created
Ah, I thought u meant literal test code, since u suggested I checked my test code
trying now
I think you are either doing something wrong or completely mis-diagnosing the issue because changing the value of a member of a reference type will absolutely update the instance being referred to 🙂
Unless you have some struct copy thing happening.
Like a classic bug is this:
and then you have code like this:
...and it doesn't get "updated" because of copy semantics with value types.
I mean based on the code I'm seeing you have a private static method that "registers types", and it's adding to a private static list/dictionary, and in that scenario, when are you calling register handlers?
I could be reading it wrong, but I'm sorta wondering how'd you'd expect something different than what is happening.
I'm invoking the listeners when an even happens:
But that is not the issue since the listeners do get correctly called
wrapper is sitting in a static dictionary
each listener isn't going to be recreated every usage.
oic what you're saying
I thought you had an activator for some reason
Yeah that's something I'll change later on, but as of now this is by design. I do think I may have find it tho. As @bighugemassive3 suggested I set a breakpoint in the constructor and I do think it's being called more than once, leaving an outdated reference in the dictionary (With it not accepting more listerners per packetId).
I'm creating the instance directly in a class member:
UdpConnection connection = new UdpConnection()
This code is being run by unity and from when I can see in the debugger it looks like it creates the instance when it compiles, but then it does it again when entering playMode which I was not aware was a thing.
@mtreit that's a closure problem with listener innit?
I still gota do a propper pass for correctly closing and disposing of everything aswell
Mayor McCheese
REPL Result: Success
Console Output
Compile: 423.742ms | Execution: 117.371ms | React with ❌ to remove this embed.
you're doing the same thing
Mayor McCheese
REPL Result: Success
Console Output
Compile: 471.284ms | Execution: 90.481ms | React with ❌ to remove this embed.
in your lambda it's looking like you're not capturing the scope, but I could be wrong
Yep, definetly this. I've now made sure to initialize the parent class on unity's start method instead of directly and works as expected.
I think the root of the problem is that the Udp class is a member of a client class that is a member of a monoBehaviour, and it trigered when compiled but it re-triggered on entering play, resulting in the old listener to ocupy the packetId spot on the dictionary
As always, it turns out to be the stupidest crap
Thank yo so much everyone for helping me out!
!solved
/close