-
-
Notifications
You must be signed in to change notification settings - Fork 22k
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
C#: Cleaner signal emission #69142
C#: Cleaner signal emission #69142
Conversation
- Add inherited xml - Remove has base stuff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for contributing!
I prefer #68233 because it allows you to override the emit methods and follows the event guidelines more closely but this is an interesting alternative.
modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
Outdated
Show resolved
Hide resolved
modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Raul Santos <raulsntos@gmail.com>
Co-authored-by: Raul Santos <raulsntos@gmail.com>
…6/godot into Cleaner-Signal-Emission-C#
My problem with this one is the need for extra allocations, one for each derived type. I understand it's needed for inheritance in order for I would have preferred this solution if it weren't for the allocations, as it does not pollute the members. |
Syntax-wise I think this can be achieved with structs + default interface implementations. That would avoid the allocations. Unfortunately, I think accessing the EDIT: Never mind... There's a limitation with structs and default interface implementations. You need to box structs in order to access default interface implementations... I love C# 🥰 |
Thats like telepathy, i thought about using structs or records with default interface implementations to. Edit: Ok, i now know what boxing means 👍 |
Seams like i accidently made something called Trigraph. 🙄
Internally, records are just classes, so they also allocate. |
I think i found something that works without the bixing issue. It's a bit hacky though. https://twitter.com/FreyaHolmer/status/1414921814564876289?t=m4g3M0ZZOoWDs12mpz0oUw&s=19 |
That's very good if it indeed works, and I wouldn't consider it hacky in my book. The downside is that extension classes can't be nested, so they pollute the namespace. |
I would just have one partial static class containing all emit extensions. |
Indeed, although it would have to be in the global namespace. Sounds good to me. I wonder what @raulsntos think of this compared to his solution. I think adding each emit method to the class pollutes the members. Specially considering we want to add them to the native types as well. That's why I gravitate more towards this |
I'd prefer to follow the .NET guidelines, I think it would be more idiomatic and would feel more familiar to .NET developers. Also, would this I kind of agree with your concern about polluting the members, which is why I wish we could just do |
I very much wish that was the case. I can't believe events have |
I think it should be public since And my goal actually was to create something similar to |
I don't see [Export]
public int PublicNumber { get; set; }
[Export]
private int _privateNumber; You'll be able to get and set both members with the GD.Print(myObj.PublicNumber); // OK
GD.Print(myObj._privateNumber); // Compiler error
GD.Print(myObj.Get("PublicNumber")); // OK
GD.Print(myObj.Get("_privateNumber")); // OK I think once you use In the same way, I think if you use If you need to emit a signal from the outside you can always expose a method in your class that emits the signal. This private-by-default approach requires you to explicitly expose the emitting methods for each signal that you want exposed so that there's intention behind it, rather than accidentally allowing outsiders from raising events which breaks OOP encapsulation.
Note that |
Ok, the way you see |
There's a problem and i can't find a good solution. For example public static void VisibilityChanged<T>(this T from) where T : Node2D.ISignalEmit
{
from.Bound.EmitSignal(Node3D.SignalName.VisibilityChanged);
}
// Makes compile error
public static void VisibilityChanged<T>(this T from) where T : Node3D.ISignalEmit
{
from.Bound.EmitSignal(Node3D.SignalName.VisibilityChanged);
} |
Generic constraints are not part of method signatures so they don't count for overload resolution. Maybe you can create a different extension class for each Node type, but I think then the method invocation would be ambiguous and would force you to be explicit by specifying the extension class in the invocation. |
That would pollute the Godot namespace a lot since you can't have a extension class as a subclass. |
I just thought about this again and I don't think that this whole But suddenly this idea came to mind: Signal.SomethingHappened.GetEmitter(this).Emit(arg);
// 'SignalName' I think should be renamed to just 'Signal' for this purpose because it will have more functionality than just retrieving the name.
// Or
Signal.SomethingHappened[this].Emit(arg);
// Or ('Signal' is 'SignalName' again)
GetSignalEmitter(SignalName.SomethingHappened).Emit(arg); All of these solutions share one main behaviour, that is getting a
Edit: The last one would be like this: GetEmitter<SignalEmmiter.SomethingHappened>().Emit(arg); |
I'd thought that emitting signals from c# does have some problems and could be a lot better.
So i made them better :)
Currently when you want to emit a signal from c# it would look something like this:
I think that this looks a bit clunky, however with this PR a property named
Emit
will be generated it is of the newly generated type calledSignalEmit
.The
SignalEmit
type works a bit like theSignalName
type and it will contain functions to quickly emit all available signals.This already looks better and is a lot more readable in my opinion.
But there is another big advantage, the parameters will match the types and the names that the signal EventHandler uses.
So when you for example add an argument or change the type of an argument from the signal EventHandler, you will instantly get error syntax highlighting and the compilation won't even accept signal emissions that would not work and break the game.