Access to ScriptComponent's IGH_DataAccess (DA)

In the ScriptComponent there’s a parameter in the InvokeRunScript signature which I would like to access from inside the ScriptComponent. Is that possible, or is the Data access entirely private? (I’m trying to find better “common ground” between ScriptComponents access level to the GH_Component in order to simplify code sync between the two)

public override void InvokeRunScript( ... IGH_DataAccess DA)

Any peep hole which I missed?

// Rolf

Oh dear. IGH_DataAccess is the public face of the internal class GH_Component.GH_StructureIterator. It’s easy to construct since it just takes an instance of the component as an argument, but both the type and the constructor are internal. You may be able to create it through Reflection of course.

Huh?

I couldn’t find any such class in the documentation nor with intellisense no matter how I tried to access it.

Huh?

Huh? I’m not very versed in meta programming in .NET. I actually don’t have a clue.

Of cource? The only course I can think of is that I’ll have to sign up for an expert level course on .NET meta programming in order to make something out this reply. :wink:

I’ve done quite some meta programming and reflection in Delphi Pascal, but not in .NET. So now I don’t have the slightest clue what you are talking about.

// Rolf

That is because of the internal modifier: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/internal

Yes, I understand that what I look for is only on a lower access level, but how do I get a handle on this single member without taking that course tonight? :slight_smile:

I promise to read up on .NET reflection, and I already started, but it doesn’t seem like I’m going to master .NET reflection to solve this specific problem before midnight…

// Rolf

I tried the following:

Type huh = typeof(GH_Component.GH_StructureIterator);

but I only get errors about the protection level

Error (CS0122): 'Grasshopper.Kernel.GH_Component.GH_StructureIterator' is inaccessible due to its protection level (line 68)

I’m lost. You guys are hiding something from me. :grinning:

// Rolf

You can not use any regular code that references that type, because it’s internal and .NET won’t allow you.

You have to find the type via reflection, find the appropriate constructor via reflection, and ultimately invoke that constructor via reflection. Everything is internal so it’s about as convoluted as reflection code gets.

constructiterator.gh (17.6 KB)

private void RunScript(object x, object y, ref object TheType, ref object TheInstance)
{
  // Grasshopper.Kernel.GH_Component.GH_StructureIterator

  Type iteratorType = null;
  Assembly grasshopperAssembly = Assembly.GetAssembly(typeof(Grasshopper.Instances));
  foreach (Type type in grasshopperAssembly.GetTypes())
    if (type.Name == "GH_StructureIterator")
    {
      iteratorType = type;
      break;
    }

  TheType = iteratorType;
  if (iteratorType != null)
  {
    object iteratorInstance = null;
    foreach (ConstructorInfo constructor in iteratorType.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic))
    {
      iteratorInstance = constructor.Invoke(new object[] { Component });
      if (iteratorInstance != null)
        break;
    }

    if (iteratorInstance != null)
    {
      Reflect(iteratorInstance);
      TheInstance = iteratorInstance;
    }
  }
}
1 Like

Thank you David,

Yes, I understand that I have to go “introvert”. I had only started to drill down with reflection and i didn’t get very far as of yet. It would have taken ages for me to arrive at your code. Thanks you very much!

Blah! :flushed:

// Rolf

I’ve written quite a lot of reflection-based code and I had to google pretty much every step along the way…

Same here, but only with Delphi Pascal, and in pascal it was a piece of cake. But in .NET world it looks like our ol’ friend Hejlsberg has gone bananas (assuming he’s the one to blame). :slight_smile:

// Rolf

Works like a charm. Absolutely perfetto!

It passed midnight but now I can happily go to sleep. < all thumbs up >

// Rolf

Incidentally you may want to cache the GH_StructureIterator and ConstructorInfo values once you’ve found them. Iterating over all the types in the Grasshopper assembly will be slow.

Yes, very slow. I made a cached property for it. Out of curiosity I tested running the GetDataAccess() method 1,000,000 (one million) times. It took 1.5 minutes according to the profiler. Same number of iterations for the property took 11 ms.

  private IGH_DataAccess m_DA;
  private IGH_DataAccess DA
  {
    get {
      if (m_DA == null)
        m_DA = GetDataAccess();
      return m_DA;
    }
  }

// Rolf

@DavidRutten,

The concept works quite well. But, my property DA (see previous post) have a problem which I don’t really understand.

Although I’m storing the retrieved IGH_DataAccess iterator in the property field m_DA (and DA works fine after that in that very Solution) it is however no longer valid in the next solution.

< scratching head >

The only way I could get it to work was to set m_DA to null and then retreive the iterator again in the next round, like so:

  protected override void BeforeSolveInstance()
   {
      // Spookish this, but I must set m_DA to null and then refresh the iterator via
      // Reflection (the DA property far below which calls `GetDataAccess()` )
      m_DA = null;
      // Data Access (property DA) is now made available for property getters, etc.
      m_DA = DA;
   }

   // Now there's a "DA" which works in the rest of the class and not only in 
   // the `SolveInstance` method.
 
   private IGH_DataAccess m_DA;
   private IGH_DataAccess DA
   {
      get {
         if (m_DA == null)
            m_DA = GetDataAccess();
         return m_DA;
      }
   }

Q: Why do I have to re-retreive and re-assign “m_DA” again every new Solution? Any idea?

// Rolf

You should cache the type, then instantiate in your BeforeSolution.