c_sharp_features.rst 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. .. _doc_c_sharp_features:
  2. Features
  3. ============
  4. This page provides an overview over the commonly used features of both C# and Godot
  5. and how they are used together.
  6. Type Conversion and Casting
  7. ---------------------------
  8. C# is a statically typed language. Therefore you can't do the following:
  9. .. code-block:: csharp
  10. var mySprite = GetNode("MySprite")
  11. mySprite.SetFrame(0)
  12. The method ``GetNode()`` returns a ``Node`` instance.
  13. You must explicitly convert it to the desired derived type, ``Sprite`` in this case.
  14. For this, you have various options in C#.
  15. **Casting and Type Checking**
  16. Throws ``InvalidCastException`` if the returned node cannot be casted to Sprite.
  17. You would use it instead of the ``as`` operator if you are pretty sure it won't fail.
  18. .. code-block:: csharp
  19. Sprite mySprite = (Sprite)GetNode("MySprite");
  20. mySprite.SetFrame(0);
  21. **Using the AS operator**
  22. The ``as`` operator returns null if the node cannot be casted to Sprite,
  23. and for this reason it cannot be used with value types.
  24. .. code-block:: csharp
  25. Sprite mySprite = GetNode("MySprite") as Sprite;
  26. // Only call SetFrame() if mySprite is not null
  27. mySprite?.SetFrame(0);
  28. **Type checking using the IS operator**
  29. To check if the node can be casted to Sprite, you can use the ``is`` operator.
  30. The ``is`` operator returns false if the node cannot be casted to Sprite,
  31. otherwise it returns true.
  32. .. code-block:: csharp
  33. if (GetNode("MySprite") is Sprite)
  34. {
  35. // Yup, it's a sprite!
  36. }
  37. For more advanced type checking, you can look into `Pattern Matching <https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching>`_.
  38. .. _c_sharp_signals:
  39. C# Signals
  40. ----------
  41. For a complete C# example, see the **Handling a signal** section in the step by step :ref:`doc_scripting` tutorial.
  42. Declaring a signal in C# is done with the ``[Signal]`` attribute on a delegate.
  43. .. code-block:: csharp
  44. [Signal]
  45. delegate void MySignal();
  46. [Signal]
  47. delegate void MySignalWithArguments(string foo, int bar);
  48. These signals can then be connected either in the editor or from code with ``Connect``.
  49. .. code-block:: csharp
  50. public void MyCallback()
  51. {
  52. GD.Print("My callback!");
  53. }
  54. public void MyCallbackWithArguments(string foo, int bar)
  55. {
  56. GD.Print("My callback with: ", foo, " and ", bar, "!");
  57. }
  58. public void SomeFunction()
  59. {
  60. instance.Connect("MySignal", this, "MyCallback");
  61. instance.Connect(nameof(MySignalWithArguments), this, "MyCallbackWithArguments");
  62. }
  63. Emitting signals is done with the ``EmitSignal`` method.
  64. .. code-block:: csharp
  65. public void SomeFunction()
  66. {
  67. EmitSignal(nameof(MySignal));
  68. EmitSignal("MySignalWithArguments", "hello there", 28);
  69. }
  70. Notice that you can always reference a signal name with the ``nameof`` keyword (applied on the delegate itself).
  71. It is possible to bind values when establishing a connection by passing an object array.
  72. .. code-block:: csharp
  73. public int Value { get; private set; } = 0;
  74. private void ModifyValue(int modifier)
  75. {
  76. Value += modifier;
  77. }
  78. public void SomeFunction()
  79. {
  80. var plusButton = (Button)GetNode("PlusButton");
  81. var minusButton = (Button)GetNode("MinusButton");
  82. plusButton.Connect("pressed", this, "ModifyValue", new object[] { 1 });
  83. minusButton.Connect("pressed", this, "ModifyValue", new object[] { -1 });
  84. }
  85. Signals support parameters and bound values of all the `built-in types <https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/built-in-types-table>`_ and Classes derived from :ref:`Godot.Object <class_Object>`.
  86. Consequently any ``Node`` or ``Reference`` will be compatible automatically but custom data objects will need to extend from `Godot.Object` or one of its subclasses.
  87. .. code-block:: csharp
  88. public class DataObject : Godot.Object
  89. {
  90. public string Field1 { get; set; }
  91. public string Field2 { get; set; }
  92. }
  93. Finally, signals can be created by calling ``AddUserSignal``, but be aware that it should be executed before any use of said signals (with ``Connect`` or ``EmitSignal``).
  94. .. code-block:: csharp
  95. public void SomeFunction()
  96. {
  97. AddUserSignal("MyOtherSignal");
  98. EmitSignal("MyOtherSignal");
  99. }