Casting Base object to a Custom type

Hi,

We have a custom object type that extends the Base object and works fine. When we send the objects to the server, the speckle_type is saved as we have defined, but when we receive it back from the server, the object is deserialized as a Base object; so, when we receive it and send it back to server once, the speckle_type is changed to Base. We are running queries based on the speckle_type and we need it to stay fixed.

Trying to expand the object and reconstruct it in GH also does not work since sometimes the id of the created object ends up different from what it was before.

Is there an easy way to cast the received object to the custom type, so that it serializes with the same hash code?

Thanks in advance.

Is your custom type getting converted to a ‘Base’ type, or is your object getting wrapped with a ‘Base’ object? If it’s the ladder, this post might help.

Could you share a link or a screenshot of the commit?

2 Likes

When deserialising, Speckle will trawl through all the loaded assemblies and look for all that are “kits”. If your custom type is defined outside a traditional “kit”, even if it’s inheriting from Base, it will not be part of the “known types” for deserialisation.

It should not that difficult to wrap things in a Speckle.Core.Kits.ISpeckleKit interface; the only thing you probably will need to implement is the Types property to return your object’s type. If you’ll give us a bit more context, we’ll be happy to help out. My burning question is where is this custom type defined :slight_smile:

Another thing to note, .NET does weird things with just in time assembly loading - so you might want to make sure to load your assembly before any deserialisation calls (sometimes a using statement might not be enough).

3 Likes

It does get wrapped in a Base object but that is not the issue. I am using the object URL to receive the object and it is received as a Base type. It is not unexpected btw; as @dimitrie pointed out, the custom type is not part of a kit, so the Receive component does not know about it; hence, the Base type. I was just wondering if it could be safely cast to the custom type since it already has all the required fields.

I’m not really sure I understand what you’re saying. If you’re using the object url you should be able to directly receive that object as a casted object type. I just tried it here with one my kits (object) and it can safely be casted to my speckle__type .

Would be interested to see how you’re handling the object conversion.

Do you have an example of how this should be handled? I’ve had a few moments of success and I’m never really sure how or what I did to make it work properly. :face_exhaling:

1 Like

Hi @dimitrie,

You are right; it is not part of any kits and is unknown for deserialization. Is it possible to safely cast it to this unknown type though?

To give it a bit of context:

We are developing a management system for a CNC shop based on Speckle. Speckle is evolving fast, and we will not maintain the system actively. Therefore, we decided to keep the Speckle Server and its Connectors intact and develop a GH plugin that will be installed on top of the Speckle. This way, we can get away with the frequent updates without recompiling our code.
We have created a library that depends on Speckle NuGets, and all the custom types and added functionality are defined in this library. We then made a GH plugin using this new library that adds a few components (including a query system and components for constructing the custom types) to the Speckle.

I will try wrapping it in an ISpeckleKit interface. However, I read this in the documentation:

When a connector needs to convert an object, it will only search for available conversion routines in the selected kit and will not automatically fall back on other kits - this might change in the future!

Am I blindly living in this propitious future? :grimacing:
I assumed I needed to override the Objects to add the custom types to it. Is it possible to have two kits and have the deserializer check both for the object type?

I am not sure how to do so in a GH plugin. I guess a dummy call to the assembly would do the trick, but since we are developing a separate plugin, I am unsure if GH loads it before or after the Speckle. Would you please elaborate a bit on this?

Sorry for the long post!
(We don’t give potatoes here, do we?)

@haitheredavid You are using a custom Kit, right?

I am NOT overriding the original Objects kit and using it as it is. I have defined the custom type as a class inheriting from Base, and it is in a totally different namespace. Therefore, it is expected to be received as Base in GH since the Receive component does not have access to this custom type.

I am now trying to see if I can cast it to the custom type explicitly. Copying the properties to a newly instantiated custom type works in some cases, but sometimes the hashed ID differs from the original object when it is sent to the server. I suspect it is because of the order of the properties or something like that. We want multiple branches in one stream to include the same object, so it is important for the ID not to change.

The reason I have not defined it as a custom Kit is that many people might want to receive the objects and send them back to the server and we did not want to deliver the custom Kit to everyone who wants to do so. Although it seems we have no other choice.

I wish I could; when this problem rears its head it’s always a bit of a mystery. I wouldn’t worry for now!

Yep :slight_smile: And you do not need to add any conversion routines if you’re not interested in your object becoming something “native” in the host application.

The gist would be:

  • deserialisation: takes text and parses it into runtime speckle objects (base-derived)
  • conversion: takes those runtime objects and converts them into Rhino objects, or Revit, etc.

Your “Kit” could be as simple as:

// your namespace
public class CustomType : Base { 
  // property declarations...
  public CustomType() { } 
}

public class CustomKit : ISpeckleKit {
  // other stuff in here...
  public IEnumerable<Type> Types => new Type[] { typeof(CustomType), typeof(OtherType) }; 
  public IEnumerable<string> Converters => new string[]{ }; // just return an empty list
}

Note: I haven’t tested this code!

4 Likes