Custom param is being replaced with Param_GenericObject

I’m a little unfamiliar with how grasshopper serializers a graph and I assume my problem is that I have not hooked up anything to handle some custom serialisation.

I have created a component which is reflection based and sets the output params to param types of my own. Basically I override the BeforeSolveInstance to grab some information about the input sources and from this register my output parameters using custom types which inherit from GH_Param but include an additional field to store some type information. Then in solve instance I set these params using some type information. Everything works well, except when I re-open a graph using this component.

My BeforeSolveInstance is check that the input source is using one of my GH_Param types so that I can access that additional field. I.e. I have an interface IGH_MyParam from which all my params inherit. The problem appears to be that either when I save or open a graph the output params in my component are being replaced with Param_GenericObject. I would have thought grasshopper would do something with my param uuids on serialisation so that upon opening a file the output params would be set to the correct type, however, I think there is something more I need to do.

Basically I’m not sure what it is I need to do so any help or a link to documentation that may help me would be much appreciated.

Also I should have included the logs on opening the file, the missing argument type of type Type that is a required parameter of my constructor for my GH_Param types.

It seems that those warnings are generated because my Params are not being registering. During serialisation my Params don’t exist in the key value pairs and therefore falls back to the GenericObject type. Unsure why this would be they all derive from GH_Param.

@DavidRutten As far as I can tell there may be a bug with restoring params for an IGH_VariableParameterComponent. The error occurs here (I hope you don’t mind me posting disassembly).

public bool ReadAllParameterData(GH_IReader reader)
{
   ...

    IGH_DocumentObject iGH_DocumentObject2 = Instances.ComponentServer.EmitObject(value4);
     f (iGH_DocumentObject2 == null)
    {
        gH_IReader.AddMessage("Parameter type is unknown", GH_Message_Type.error);
        flag = false;
        iGH_DocumentObject2 = new Param_GenericObject();
    }
}

As far as i can tell the ComponentServer does not include the params defined in a plugin? Basically the Instances.ComponentServer.EmitObject(value4) fails to find the param defined by the plugin, even though the Guid is correct. Therefore, it falls back to the Param_GenericObject

Maybe this is a little niche and not worth addressing. I’ve opted to instead override the Read method on my component as all the data is serialised correct but because my RegisterOutputParams contains no logic the behaviour of the GH_Component behaviour (i.e. removing the IGH_VariableParameterComponent intermittence) is also not suitable for my case. Therefore I can read the applicable data and register the correct output params based on the Guids that were serialised using my own mapping.

The ComponentServer will not contain parameters which cannot be instantiated. For example parameters which lack a public, empty constructor, or parameters which have a generic constraint. Or which are internal.

Is that the case with the parameters here? Do they show up in the list of search results when you double click and type?

Ok I was curious why they did not show up in the search too. The are derived from a generic constraint, but not generic themself (as I guess most params are). They do not however have an empty constructor. Thanks!

But just FYI, in the end I opted to not use IGH_VariableParameterComponent. The outputs are not user variable, but are set in BeforeSolveInstance based on Sources. So in the end I opted for the standard GH_Component serialisation and including the Param ComponentGuid in serialisation so that I could effectively run logic similar to RegisterOutputParams before calling base.Read(), which in the end was a cleaner solution (so maybe a good thing I ran into this problem and had to rethink my implementation).

Yep.