Default behaviour associated with custom class and passing data to a different component

Hello everyone.

Can someone clarify for me the default behaviour associated with inputting new class defined in one component into the different component in the same Name Space of the Visual Studio project.

A bit more detail:

I developed several components within the same namespace. To aggregate outputs of these components I created specific classes associated with each developed component, that contains fields corresponding to all the desired outputs of the component, and several methods that operate on these fields.

Most of the developed components can receive these classes as an input via GH_ ObjectWrapper :

GH_ObjectWrapper obj_wrap_arc = new GH_ObjectWrapper();

if (!DA.GetData(ret_ind, ref obj_wrap_arc)) { return; }

ARCH_Data ARCH = obj_wrap_arc.Value as ARCH_Data;

And for optional inputs

bool PR_l_flag = true;

PR_Data PR_l = new PR_Data();

GH_ObjectWrapper obj_wrap_pr_l = new GH_ObjectWrapper();

if (!DA.GetData(ret_ind, ref obj_wrap_pr_l)) { PR_l_flag = false; }

else { PR_l = obj_wrap_pr_l.Value as PR_Data; }

One of the components not only receives values as inputs, but also, performs modification on the received class.

Lets say I have a field num_id (integer array) in PR_l.

I do the following operation on it:

for(ii = 0; ii < PR_l.num_id.Length; ii++) { PR_l.num_id[ii] += 100;}

I thought that (in this case) PR_l would be a deep copy of the inputs, and as such changes to it would not affect the original inputs. What I observed on the other hand is when the component runs again values of num_id , are already incremented by 100.

Is there an easy way to address this issue?

Assume that in one C# component you declare a custom Class [as shown: of type geoInfo] …

… and then you output some geoInfo type List.

Assume that in another C# component you declare the very same class and using a List of type object (as shown: the cList) you receive data from the “donor” component:

Then do:

1 Like

You can probably ditch the GH_ObjectWrapper stuff and just directly use object.

object obj = default;
if (!DA.GetData(ret_ind, ref obj)) return;

switch (obj)
  case ARCH_Data arch:
  case COLUMN_Data col:
  case etc. etc.

There is no good mechanism in .NET for creating deep copies (IClonable is not strongly typed, and anyway not many objects implement it), so you definitely have to create your own copies if you modify data.

If your types are just collections of values, you can use struct instead of class, which makes copying easier.

Thank you David.
I have implemented my own code for copying my class contents ( a lot of overloading and generic type functions). The switch usage example was quite helpful for that.
On a related note, how can I check if Rhino/Grasshopper class is value or reference based?
I got curious because behaviour for:
List pnt_lst = new List(old_pnt_lst);
List NS_lst = new List(old_NS_lst);
Using structures, might be a good idea, I will look into it.
is different, with Point list generating a new instance for each point, while NurbsSurface list just creates a reference to the old surfaces.

If you can assign null to a value, its a reference type (i.e. a class). Also the documentation will say so, as will the visual studio object browser.

1 Like