##################
C# Wrapper Classes
##################

In addition to :doc:`the direct bindings to HOOPS Exchange binaries <bindings>`, the C# API provides high-level classes called *wrappers*.

Wrapper classes encapsulate both the entity handle and a local copy of its data structure, providing a C#-idiomatic interface to HOOPS Exchange.
For example, a model file entity managed by an ``A3DAsmModelFile``/``A3DAsmModelFileData`` set has a wrapper class called ``A3DAsmModelFileWrapper``.

These classes offer features such as constructors, resource management, inheritance, and properties.
However, the current version of the C# API limits wrappers to short-lived, read-only entities. For other functionalities, you can still fallback to :doc:`call bindings <bindings>`.

.. rubric:: Comparison with Struct Bindings

Wrapper classes enhance the :ref:`struct bindings <cs_bindings_structs>` by providing:

* :ref:`Simplified struct initialization <cs_wrapper_init>`
* :ref:`Automatic data loading <cs_wrapper_load>`
* :ref:`Memory management <cs_wrapper_dispose>`
* :ref:`C# properties for seamless access <cs_wrapper_properties>`
* Methods for entity :ref:`creation <cs_wrapper_create>` and :ref:`editing <cs_wrapper_edit>`

.. _cs_wrapper_init:

Struct Initialization
=====================

Wrapper classes provide default constructors that initialize internal data structures using ``API.Initialize()``.

.. tabs::

   .. tab:: C# (Wrapper Class)

      .. code-block:: cs

         var export_params = new A3DRWParamsExportXMLDataWrapper();

   .. tab:: C# (Binding Layer)

      .. code-block:: cs

         A3DRWParamsExportXMLData export_params;
         API.Initialize(out export_params);
         
   .. tab:: C

      .. code-block:: c

         A3DRWParamsExportXMLData export_params = A3D_MAKE_DATA(A3DRWParamsExportXMLData);

.. _cs_wrapper_load:

Data Load
=========

When instantiated with an entity handle, wrapper classes automatically load entity data into the internal structure:

.. tabs::

   .. tab:: C# (Wrapper Class)

      .. code-block:: cs

         var model_file = new A3DAsmModelFileWrapper(model_file_handle);

   .. tab:: C# (Binding Layer)

      .. code-block:: cs

         A3DAsmModelFileData model_file_data;
         API.Initialize(out model_file_data);
         
         API.A3DAsmModelFileGet(model_file_handle, ref model_file_data);

   .. tab:: C

      .. code-block:: c

         A3DAsmModelFileData model_file_data = A3D_MAKE_DATA(A3DAsmModelFileData);
         
         A3DAsmModelFileGet(model_file_handle, &model_file_data);

.. _cs_wrapper_dispose:

Memory Management
=================

Wrapper classes implement the `IDisposable <https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-idisposable>`__ interface to manage unmanaged resources. To free resources, call ``Dispose()`` explicitly:

.. tabs::

   .. tab:: C# (Wrapper Class)

      .. code-block:: cs

         var model_file = new A3DAsmModelFileWrapper(model_file_handle);

         // Use the model file
         model_file.Dispose();

   .. tab:: C# (Binding Layer)

      .. code-block:: cs

         A3DAsmModelFileData model_file_data;
         API.Initialize(out model_file_data);
         
         API.A3DAsmModelFileGet(model_file_handle, ref model_file_data);

         // Use the model file
         API.A3DAsmModelFileGet(IntPtr.Zero, ref model_file_data);

   .. tab:: C

      .. code-block:: c

         A3DAsmModelFileData model_file_data = A3D_MAKE_DATA(A3DAsmModelFileData);
         
         A3DAsmModelFileGet(model_file_handle, &model_file_data);

         // Use the model file
         A3DAsmModelFileGet(0, &model_file_data);

Alternatively, use the `using` statement to ensure automatic disposal:

.. code-block:: cs

   using (var model_file = new A3DAsmModelFileWrapper(model_file_handle))
   {
       // Use the model file
   }

For details, see `Using objects that implement IDisposable (MSDN) <https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/using-objects>`__.

.. _cs_wrapper_properties:

Properties
==========

Wrapper classes expose fields of data structures as `C# Properties <https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties>`__:

.. tabs::

   .. tab:: C# (Wrapper Class)

      .. code-block:: cs

         var model_file = new A3DAsmModelFileWrapper(model_file_handle);

         bool unit_from_cad = model_file.m_bUnitFromCAD; // Property get

   .. tab:: C# (Binding Layer)

      .. code-block:: cs

         A3DAsmModelFileData model_file_data;
         API.Initialize(out model_file_data);
         
         API.A3DAsmModelFileGet(model_file_handle, ref model_file_data);

         bool unit_from_cad = model_file_data.m_bUnitFromCAD;

   .. tab:: C

      .. code-block:: c

         A3DAsmModelFileData model_file_data = A3D_MAKE_DATA(A3DAsmModelFileData);
         
         A3DAsmModelFileGet(model_file_handle, &model_file_data);

         A3DBool unit_from_cad = model_file_data.m_bUnitFromCAD;

Properties include both ``get`` and ``set`` accessors. 
Array properties are automatically converted to and from unmanaged C-style arrays using :doc:`utils`.
The example below shows how to retrieve a list of child product occurrences as an ``IntPtr[]``:

.. tabs::

   .. tab:: C# (Wrapper Class)

      .. code-block:: cs

         var product_occurrence = new A3DAsmProductOccurrence(product_occurrence_handle);

         IntPtr[] children_handles = product_occurrence.m_ppPOccurrences;

   .. tab:: C# (Binding Layer)

      .. code-block:: cs

         A3DAsmProductOccurrenceData product_occurrence_data;
         API.Initialize(out product_occurrence_data);
         
         API.A3DAsmModelFileGet(product_occurrence_handle, ref product_occurrence_data);

         IntPtr[] children_handles = ArrayWrapper.ReadIntPtrArray(
             product_occurrence_data.m_ppPOccurrences,
             product_occurrence_data.m_uiPOccurrencesSize
         );

.. _cs_wrapper_create:

Entity Creation
===============

Wrapper classes provide a ``Create()`` method to encapsulate the entity creation process:

.. tabs::

   .. tab:: C# (Wrapper Class)

      .. code-block:: cs

         var model_file = new A3DAsmModelFileWrapper();

         model_file.Create();

   .. tab:: C# (Binding Layer)

      .. code-block:: cs

         A3DAsmModelFileData model_file_data;
         API.Initialize(out model_file_data);
         
         IntPtr model_file_handle = IntPtr.Zero;
         API.A3DAsmModelFileCreate(ref model_file_data, out model_file_handle);

   .. tab:: C

      .. code-block:: c

         A3DAsmModelFileData model_file_data = A3D_MAKE_DATA(A3DAsmModelFileData);
         
         A3DAsmModelFile model_file_handle = 0;
         A3DAsmModelFileCreate(&model_file_data, &model_file_handle);

.. _cs_wrapper_edit:

Entity Edition
==============

If an entity supports editing, wrapper classes provide an ``Edit()`` method:

.. tabs::

   .. tab:: C# (Wrapper Class)

      .. code-block:: cs

         // ...

         model_file.Edit();

   .. tab:: C# (Binding Layer)

      .. code-block:: cs

         // ...

         API.A3DAsmModelFileEdit(ref model_file_data, model_file_handle);

   .. tab:: C

      .. code-block:: c

         // ...

         A3DAsmModelFileEdit(&model_file_data, model_file_handle);
