فهرست منبع

Add C# collections documentation page

- Move documentation of the Godot C# collection types to a dedicated page.
- Document the differences between .NET collections and Godot collections.
- Help users choose which type of collection to use in C#.
Raul Santos 2 سال پیش
والد
کامیت
c403465613

+ 234 - 0
tutorials/scripting/c_sharp/c_sharp_collections.rst

@@ -0,0 +1,234 @@
+.. _doc_c_sharp_collections:
+
+C# collections
+==============
+
+Choose a collection
+-------------------
+
+The .NET base class library contains multiple collection types that can be
+used to store and manipulate data. Godot also provide some collection types.
+
+The main difference between the `.NET collections <https://learn.microsoft.com/en-us/dotnet/standard/collections/>`_
+and the Godot collections is that the .NET collections are implemented in C# while
+the Godot collections are implemented in C++ and the Godot C# API is a wrapper over it,
+this is an important distinction since it means every operation on a Godot collection
+requires marshaling which can be expensive specially inside in a loop.
+
+Due to the performance implications, using Godot collections is only recommended
+when absolutely necessary (such as interacting with the Godot API). Godot only
+understands its own collection types, so it's required to use them when talking
+to the engine.
+
+If you have a collection of elements that don't need to be passed to a Godot API,
+using a .NET collection would be more performant.
+
+.. tip::
+
+    It's also possible to convert between .NET collections and Godot collections.
+    The Godot collections contain constructors from generic .NET collection interfaces
+    that copy their elements, and the Godot collections can be used with the
+    `LINQ <https://learn.microsoft.com/en-us/dotnet/standard/linq>`_
+    ``ToList``, ``ToArray`` and ``ToDictionary`` methods. But keep in mind this conversion
+    requires marshaling every element in the collection and copies it to a new collection
+    so it can be expensive.
+
+Despite this, the Godot collections are optimized to try and avoid unnecessary
+marshaling, so methods like ``Sort`` or ``Reverse`` are implemented with a single
+interop call and don't need to marshal every element. Keep an eye out for generic APIs
+that take collection interfaces like `LINQ <https://learn.microsoft.com/en-us/dotnet/standard/linq>`_
+because every method requires iterating the collection and, therefore, marshaling
+every element. Prefer using the instance methods of the Godot collections when possible.
+
+To choose which collection type to use for each situation, consider the following questions:
+
+* Does your collection need to interact with the Godot engine?
+  (e.g.: the type of an exported property, calling a Godot method).
+
+   * If yes, since Godot only supports :ref:`Variant-compatible <doc_c_sharp_variant>`
+     types, use a Godot collection.
+   * If not, consider `choosing an appropiate .NET collection <https://learn.microsoft.com/en-us/dotnet/standard/collections/selecting-a-collection-class>`_.
+
+* Do you need a Godot collection that represents a list or sequential set of data?
+
+   * Godot :ref:`arrays <doc_c_sharp_collections_array>` are similar to the C# collection ``List<T>``.
+   * Godot :ref:`packed arrays <doc_c_sharp_collections_packedarray>` are more memory-efficient arrays,
+     in C# use one of the supported ``System.Array`` types.
+
+* Do you need a Godot collection that maps a set of keys to a set of values?
+
+   * Godot :ref:`dictionaries <doc_c_sharp_collections_dictionary>` store pairs of keys and values
+     and allow easy access to the values by their associated key.
+
+Godot collections
+-----------------
+
+.. _doc_c_sharp_collections_packedarray:
+
+PackedArray
+^^^^^^^^^^^
+
+Godot packed arrays are implemented as an array of a specific type, allowing it to be
+more tightly packed as each element has the size of the specific type, not ``Variant``.
+
+In C#, packed arrays are replaced by ``System.Array``:
+
+======================  ==============================================================
+GDScript                C#
+======================  ==============================================================
+``PackedInt32Array``    ``int[]``
+``PackedInt64Array``    ``long[]``
+``PackedByteArray``     ``byte[]``
+``PackedFloat32Array``  ``float[]``
+``PackedFloat64Array``  ``double[]``
+``PackedStringArray``   ``string[]``
+``PackedColorArray``    ``Color[]``
+``PackedVector2Array``  ``Vector2[]``
+``PackedVector3Array``  ``Vector3[]``
+======================  ==============================================================
+
+Other C# arrays are not supported by the Godot C# API since a packed array equivalent
+does not exist. See :ref:`Variant <doc_c_sharp_variant>` for a list of all the compatible
+types.
+
+.. _doc_c_sharp_collections_array:
+
+Array
+^^^^^
+
+Godot arrays are implemented as an array of ``Variant`` and can contain several elements
+of any type. In C#, the equivalent type is ``Godot.Collections.Array``.
+
+The generic ``Godot.Collections.Array<T>`` type allows restricting the element type to
+a :ref:`Variant-compatible <doc_c_sharp_variant>` type.
+
+An untyped ``Godot.Collections.Array`` can be converted to a typed array using the
+``Godot.Collections.Array<T>(Godot.Collections.Array)`` constructor.
+
+.. note::
+
+    Despite the name, Godot arrays are more similar to the C# collection
+    ``List<T>`` than ``System.Array``. Their size is not fixed and can grow
+    or shrink as elements are added/removed from the collection.
+
+List of Godot's Array methods and their equivalent in C#:
+
+=======================  ==============================================================
+GDScript                 C#
+=======================  ==============================================================
+all                      `System.Linq.Enumerable.All`_
+any                      `System.Linq.Enumerable.Any`_
+append                   Add
+append_array             AddRange
+back                     ``Array[^1]`` or `System.Linq.Enumerable.Last`_ or `System.Linq.Enumerable.LastOrDefault`_
+bsearch                  BinarySearch
+bsearch_custom           N/A
+clear                    Clear
+count                    `System.Linq.Enumerable.Count`_
+duplicate                Duplicate
+erase                    Remove
+fill                     Fill
+filter                   Use `System.Linq.Enumerable.Where`_
+find                     IndexOf
+front                    ``Array[0]`` or `System.Linq.Enumerable.First`_ or `System.Linq.Enumerable.FirstOrDefault`_
+get_typed_builtin        N/A
+get_typed_class_name     N/A
+get_typed_script         N/A
+has                      Contains
+hash                     GD.Hash
+insert                   Insert
+is_empty                 Use ``Count == 0``
+is_read_only             IsReadOnly
+is_typed                 N/A
+make_read_only           MakeReadOnly
+map                      `System.Linq.Enumerable.Select`_
+max                      Max
+min                      Min
+pick_random              PickRandom (Consider using `System.Random`_)
+pop_at                   ``Array[i]`` with ``RemoveAt(i)``
+pop_back                 ``Array[^1]`` with ``RemoveAt(Count - 1)``
+pop_front                ``Array[0]`` with ``RemoveAt(0)``
+push_back                ``Insert(Count, item)``
+push_front               ``Insert(0, item)``
+reduce                   `System.Linq.Enumerable.Aggregate`_
+remove_at                RemoveAt
+resize                   Resize
+reverse                  Reverse
+rfind                    LastIndexOf
+shuffle                  Shuffle
+size                     Count
+slice                    Slice
+sort                     Sort
+sort_custom              `System.Linq.Enumerable.OrderBy`_
+typed_assign             N/A
+operator !=              !RecursiveEqual
+operator +               operator +
+operator <               N/A
+operator <=              N/A
+operator ==              RecursiveEqual
+operator >               N/A
+operator >=              N/A
+operator []              Array[int] indexer
+=======================  ==============================================================
+
+.. _System.Random: https://learn.microsoft.com/en-us/dotnet/api/system.random
+.. _System.Linq.Enumerable.Aggregate: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.aggregate
+.. _System.Linq.Enumerable.All: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.all
+.. _System.Linq.Enumerable.Any: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.any
+.. _System.Linq.Enumerable.Count: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.count
+.. _System.Linq.Enumerable.First: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.first
+.. _System.Linq.Enumerable.FirstOrDefault: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.firstordefault
+.. _System.Linq.Enumerable.Last: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.last
+.. _System.Linq.Enumerable.LastOrDefault: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.lastordefault
+.. _System.Linq.Enumerable.OrderBy: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.orderby
+.. _System.Linq.Enumerable.Select: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.select
+.. _System.Linq.Enumerable.Where: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.where
+
+.. _doc_c_sharp_collections_dictionary:
+
+Dictionary
+^^^^^^^^^^
+
+Godot dictionaries are implemented as a dictionary with ``Variant`` keys and values.
+In C#, the equivalent type is ``Godot.Collections.Dictionary``.
+
+The generic ``Godot.Collections.Dictionary<TKey, TValue>`` type allows restricting the key
+and value types to a :ref:`Variant-compatible <doc_c_sharp_variant>` type.
+
+An untyped ``Godot.Collections.Dictionary`` can be converted to a typed dictionary using the
+``Godot.Collections.Dictionary<TKey, TValue>(Godot.Collections.Dictionary)`` constructor.
+
+.. tip::
+
+    If you need a dictionary where the key is typed but not the value, use
+    ``Variant`` as the ``TValue`` generic parameter of the typed dictionary.
+
+    .. code-block:: csharp
+
+        // The keys must be string, but the values can be any Variant-compatible type.
+        var dictionary = new Godot.Collections.Dictionary<string, Variant>();
+
+List of Godot's Dictionary methods and their equivalent in C#:
+
+=======================  ==============================================================
+GDScript                 C#
+=======================  ==============================================================
+clear                    Clear
+duplicate                Duplicate
+erase                    Remove
+find_key                 N/A
+get                      Dictionary[Variant] indexer or TryGetValue
+has                      ContainsKey
+has_all                  N/A
+hash                     GD.Hash
+is_empty                 Use ``Count == 0``
+is_read_only             IsReadOnly
+keys                     Keys
+make_read_only           MakeReadOnly
+merge                    Merge
+size                     Count
+values                   Values
+operator !=              !RecursiveEqual
+operator ==              RecursiveEqual
+operator []              Dictionary[Variant] indexer, Add or TryGetValue
+=======================  ==============================================================

+ 10 - 118
tutorials/scripting/c_sharp/c_sharp_differences.rst

@@ -776,136 +776,28 @@ GDScript              C#
 Array
 -----
 
-*This is temporary. PackedArrays will need their own types to be used the way they are meant to.*
-
-======================  ==============================================================
-GDScript                C#
-======================  ==============================================================
-``Array``                ``Godot.Collections.Array``
-``PackedInt32Array``     ``int[]``
-``PackedInt64Array``     ``long[]``
-``PackedByteArray``      ``byte[]``
-``PackedFloat32Array``   ``float[]``
-``PackedFloat64Array``   ``double[]``
-``PackedStringArray``    ``string[]``
-``PackedColorArray``     ``Color[]``
-``PackedVector2Array``   ``Vector2[]``
-``PackedVector3Array``   ``Vector3[]``
-======================  ==============================================================
+The equivalent of packed arrays are ``System.Array``.
 
-``Godot.Collections.Array<T>`` is a type-safe wrapper around ``Godot.Collections.Array``.
-Use the ``Godot.Collections.Array<T>(Godot.Collections.Array)`` constructor to create one.
-
-List of Godot's Array methods and their equivalent in C#:
+See also :ref:`PackedArray in C# <doc_c_sharp_collections_packedarray>`.
 
-=======================  ==============================================================
-GDScript                 C#
-=======================  ==============================================================
-all                      `System.Linq.Enumerable.All`_
-any                      `System.Linq.Enumerable.Any`_
-append                   Add
-append_array             AddRange
-back                     ``Array[^1]`` or `System.Linq.Enumerable.Last`_ or `System.Linq.Enumerable.LastOrDefault`_
-bsearch                  BinarySearch
-bsearch_custom           N/A
-clear                    Clear
-count                    `System.Linq.Enumerable.Count`_
-duplicate                Duplicate
-erase                    Remove
-fill                     Fill
-filter                   Use `System.Linq.Enumerable.Where`_
-find                     IndexOf
-front                    ``Array[0]`` or `System.Linq.Enumerable.First`_ or `System.Linq.Enumerable.FirstOrDefault`_
-get_typed_builtin        N/A
-get_typed_class_name     N/A
-get_typed_script         N/A
-has                      Contains
-hash                     GD.Hash
-insert                   Insert
-is_empty                 Use ``Count == 0``
-is_read_only             IsReadOnly
-is_typed                 N/A
-make_read_only           MakeReadOnly
-map                      `System.Linq.Enumerable.Select`_
-max                      Max
-min                      Min
-pick_random              PickRandom (Consider using `System.Random`_)
-pop_at                   ``Array[i]`` with ``RemoveAt(i)``
-pop_back                 ``Array[^1]`` with ``RemoveAt(Count - 1)``
-pop_front                ``Array[0]`` with ``RemoveAt(0)``
-push_back                ``Insert(Count, item)``
-push_front               ``Insert(0, item)``
-reduce                   `System.Linq.Enumerable.Aggregate`_
-remove_at                RemoveAt
-resize                   Resize
-reverse                  Reverse
-rfind                    LastIndexOf
-shuffle                  Shuffle
-size                     Count
-slice                    Slice
-sort                     Sort
-sort_custom              `System.Linq.Enumerable.OrderBy`_
-typed_assign             N/A
-operator !=              !RecursiveEqual
-operator +               operator +
-operator <               N/A
-operator <=              N/A
-operator ==              RecursiveEqual
-operator >               N/A
-operator >=              N/A
-operator []              Array[int] indexer
-=======================  ==============================================================
+Use ``Godot.Collections.Array`` for an untyped ``Variant`` array.
+``Godot.Collections.Array<T>`` is a type-safe wrapper around ``Godot.Collections.Array``.
 
-.. _System.Random: https://learn.microsoft.com/en-us/dotnet/api/system.random
-.. _System.Linq.Enumerable.Aggregate: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.aggregate
-.. _System.Linq.Enumerable.All: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.all
-.. _System.Linq.Enumerable.Any: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.any
-.. _System.Linq.Enumerable.Count: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.count
-.. _System.Linq.Enumerable.First: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.first
-.. _System.Linq.Enumerable.FirstOrDefault: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.firstordefault
-.. _System.Linq.Enumerable.Last: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.last
-.. _System.Linq.Enumerable.LastOrDefault: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.lastordefault
-.. _System.Linq.Enumerable.OrderBy: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.orderby
-.. _System.Linq.Enumerable.Select: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.select
-.. _System.Linq.Enumerable.Where: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.where
+See also :ref:`Array in C# <doc_c_sharp_collections_array>`.
 
 Dictionary
 ----------
 
-Use ``Godot.Collections.Dictionary``.
-
-``Godot.Collections.Dictionary<T>`` is a type-safe wrapper around ``Godot.Collections.Dictionary``.
-Use the ``Godot.Collections.Dictionary<T>(Godot.Collections.Dictionary)`` constructor to create one.
+Use ``Godot.Collections.Dictionary`` for an untyped ``Variant`` dictionary.
+``Godot.Colelctions.Dictionary<TKey, TValue>`` is a type-safe wrapper around ``Godot.Collections.Dictionary``.
 
-List of Godot's Dictionary methods and their equivalent in C#:
-
-=======================  ==============================================================
-GDScript                 C#
-=======================  ==============================================================
-clear                    Clear
-duplicate                Duplicate
-erase                    Remove
-find_key                 N/A
-get                      Dictionary[Variant] indexer or TryGetValue
-has                      ContainsKey
-has_all                  N/A
-hash                     GD.Hash
-is_empty                 Use ``Count == 0``
-is_read_only             IsReadOnly
-keys                     Keys
-make_read_only           MakeReadOnly
-merge                    Merge
-size                     Count
-values                   Values
-operator !=              !RecursiveEqual
-operator ==              RecursiveEqual
-operator []              Dictionary[Variant] indexer, Add or TryGetValue
-=======================  ==============================================================
+See also :ref:`Dictionary in C# <doc_c_sharp_collections_dictionary>`.
 
 Variant
 -------
 
-``Godot.Variant`` is used to represent Godot's native :ref:`Variant <class_Variant>` type. Any Variant-compatible type can be converted from/to it.
+``Godot.Variant`` is used to represent Godot's native :ref:`Variant <class_Variant>` type.
+Any Variant-compatible type can be converted from/to it.
 
 See also: :ref:`doc_c_sharp_variant`.
 

+ 1 - 0
tutorials/scripting/c_sharp/index.rst

@@ -8,6 +8,7 @@ C#
    c_sharp_basics
    c_sharp_features
    c_sharp_differences
+   c_sharp_collections
    c_sharp_variant
    c_sharp_signals
    c_sharp_exports