-
-
Notifications
You must be signed in to change notification settings - Fork 21.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Signal connections established with +=
are not automatically removed when receiver is destroyed
#70414
Comments
Is this operator overload for connecting signals documented anywhere? I don't remember seeing this in GDScript. Why was it added? |
At least in the getting started section it is done with |
It's probably caused by the generated implementation for the signal: private global::Sender.MySignalEventHandler backing_MySignal;
/// <inheritdoc cref="global::Sender.MySignalEventHandler"/>
public event global::Sender.MySignalEventHandler MySignal {
add => backing_MySignal += value;
remove => backing_MySignal -= value;
} This wil just add the new event handler as a multicast target to the backing event handler, so the engine will not even know that the signal is connected. I checked that by printing the amount of signal connections in the sender. When using the One solution could be to actually call "Connect" / Disconnect in the generated method and not use a "backing" signal delegate: public event global::Sender.MySignalEventHandler MySignal {
add => Connect(nameof(MySignal), Callable.From(value));
remove => Disconnect(nameof(MySignal), Callable.From(value)); // this will actually not work as it is a new callable
} but you would need a way to transform the delegate type into a Callable plus you would need some kind of bookkeeping between the |
It is the current recommended way of connecting signals in C# and was introduced to replicate the built-in observer pattern in the C# language. You can see some examples here. |
Are there any news about this issue? |
additional: it also throws like this: Sender.Connect(nameof(Sender.MySignal), Callable.From(()=>{GD.Print("hello")})); or void sayHello()
{
GD.Print("hello")
}
Sender.Connect(nameof(Sender.MySignal), Callable.From(sayHello)); |
Any news on this problem? I'm experiencing it as well and think it's quite a nasty one as the documentation is filled with event connecting examples instead of .Connect(). |
See the linked PR: |
I see, thank you very much! |
This issue is over a year old. Given the nasty set of bugs it silently produces, should it be either:
At the very least, it would be useful to provide a non- |
About a month ago, I contributed some PRs to the C# signals doc to describe the behavior with some more detail. However, it's only available in PTAL and send some followup PRs if you can make it clearer! I've gotten feedback that the example is a bit too contrived and makes it hard to follow the rest of it, but I haven't had a chance to go back and see if I can make it better by giving more context or using a more gamedev-linked example. |
@31 thanks for the link, your additions are a huge improvement to the docs in that section! I especially appreciate the detailed info about what's happening and when using |
Appreciate the work that has gone into the updated documentation for 4.3, and the information collected to this point. Took a fair bit of digging to find out what my issue was with an Seems like this is a reasonable priority to address in a future release, not just updating the documentation with the workarounds. |
Agreed @tm76, given that signals are such a core part of Godot, most C# users would likely be surprised that they aren't rock solid / have so many gotchas. |
As you said in the latest doc that using Connect will disconnect automatically with custom signals, while using += needs manual disconnection, I wonder whether connecting through Godot Editor Inspector equals using Connect method?Thank you! |
@HymnStudio I think editor signal connections indeed equals those using Connect(). The test I've done:
|
Godot version
v4.0.beta9.mono.official [e780dc3]
System information
Windows 10
Issue description
Assume you create a custom node class which emits a signal every second:
Now you have a receiver which connects to this signal either with the classic "Connect" method or with the new
+=
syntax. The receiver destroys itself after a few seconds:Either way, I would expect that the signal is automatically disconnected when when the receiver is destroyed. This works when using the
Connect
method, but doesn't work when using the+=
method. In the latter case the signal connection stays and the sender throws an exception when it emits the signal the next time:It looks like the sender tries to invoke a callback on the now disposed receiver. Again this works fine when using
Connect
to connect the signal.Steps to reproduce
In the example project open the sender.tscn scene and run it. You can see in the output that the receiver receives two signals before it self destructs.
After that you can see the exception raised in the sender:
When you switch the receiver to use "Connect" using the inspector:
Then everything works as expected.
Minimal reproduction project
example.zip
The text was updated successfully, but these errors were encountered: