Calling a method in a parent class of a newly added generic component (C#)

I’ve searched for generic classes and found out about instantiating generic classes but I haven’t been able to find an answer to what I’m looking for. Hopefully someone more skilled can shed some light at how to perform this.

Question:
What I want to do is 1) add a component of a generic type and then 2) call a method in that component that I know exists in a parent class of that component.

Pseudo Code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// Manager.cs
public class ManagerClass : MonoBehaviour
{
    void Awake()
    {
        GameObject _g = new GameObject();
        // The string "DerivedClass2" could be any string which I don't know at this point - the example uses DerivedClass2 as an example.
        System.Type _anyDerivedClass = System.Type.GetType("DerivedClass2");

        // BEGIN QUESTION This is what I want to do - pseudo code which doesn't work :)
        _anyDerivedClass.GetType() _c = _g.AddComponent(_anyDerivedClass);
        _c.Import();
        // END QUESTION

    }
}

// BaseClass.cs
public class BaseClass : MonoBehaviour
{
    public virtual void Import()
    {
        // Perform import here
    }
}

// DerivedClass1.cs
public class DerivedClass1 : BaseClass
{

}

// DerivedClass2.cs
public class DerivedClass2 : BaseClass
{

}

The virtual method will exist in the derived class. That’s not an example of anything “generic”, though.
You’re already using the type in your GetType(“Name Here”) portion of code, I don’t see why you wouldn’t just do:

DerivedClass2 dc2 = _g.AddComponent<DerivedClass2>();
dc2.Import();
1 Like

Thanks, for your reply. I would like to keep the code generic because in the Manager, the same method should be able to add component of N number of derived classes and call the Import method of that class (that exists in the parent). Also, a JSON string will contain the name of the class as a string which is why I don’t know the actual class. I can work around the problem without generic code using if statements to find class and cast it, e.g.:

if (_anyDerivedClass == typeof(DerivedClass1))
  ((DerivedClass1) _anyDerivedClass).Import();
if (_anyDerivedClass == typeof(DerivedClass2))
  ((DerivedClass2) _anyDerivedClass).Import();

…but it wouldn’t be pretty nor would it scale well.

If you can guarantee that the instantiated component is a child of your base class then you can type cast it. You can use Type.IsSubclassOf to do the first part of that.

if (_anyDerivedClass.IsSubclassOf(typeof(BaseClass)))
{
  BaseClass _c = (BaseClass)g.AddComponent(_anyDerivedClass);
  _c.Import();
}
else
{
  // fail
}

Syntax might be a bit off, but that’s the general idea.

1 Like

I see - now I understand the reason for the string. I believe you should use the type after you got it from the string version of GetType() (ie: not use “.GetType()” again on the next line).

1 Like

Thanks Dave-Carlile, it’s a guarantee to be a subclass so “IsSubclassOf” did the trick.

For reference, this is an updated pseudo version:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// Manager.cs
public class ManagerClass : MonoBehaviour
{
    void Awake()
    {
        GameObject _g = new GameObject();
        // The string "DerivedClass2" could be any string which I don't know at this point - the example uses DerivedClass2 as an example.
        System.Type _anyDerivedClass = System.Type.GetType("DerivedClass2");

        // SOLUTION (thank Dave-Carlile)
        if (_anyDerivedClass.IsSubclassOf(typeof(_anyDerivedClass))
        {
            BaseClass _c = (BaseClass) _g.AddComponent(_anyDerivedClass);
            _c.Import();
        }
        // END SOLUTION

    }
}

// BaseClass.cs
public class BaseClass : MonoBehaviour
{
    public virtual void Import()
    {
        // Perform import here
    }
}

// DerivedClass1.cs
public class DerivedClass1 : BaseClass
{

}

// DerivedClass2.cs
public class DerivedClass2 : BaseClass
{

}

In my project the actual code segment looks like this (I’m using SimpleJSON) and when I loop through a string containing multiple blueprints it’ll instantiate a new GameObject, add the appropriate blueprint component, and import the actual configuration of that blueprint from the subsection of JSON.

            // Parse the JSON string
            var N = JSON.Parse(_str);

            int _i = 0;
            while (N["item" + _i] != null)
            {
                    GameObject _go = new GameObject();
                    System.Type _blueprintClass = System.Type.GetType("ProceduralPlanets." + N["item" + _i]["type"]);

                    if (_blueprintClass.IsSubclassOf(typeof(BlueprintPlanet)))
                    {
                        BlueprintPlanet _c = (BlueprintPlanet)_go.AddComponent(_blueprintClass);
                        _c.ImportFromJSON(N["item" + _i].ToString());
                    }
                    _i++;
           }

(I omitted some validation code)

Just for completion’s sake, I would have thought that…

_blueprintClass bp = _go.AddComponent<_blueprintClass>();

would have worked, too.

Regardless, I’m glad that you got it working :slight_smile:

Thanks! I didn’t seem to be able to use _blueprintClass like that. I get the error: ‘_blueprintClass’ is a variable but is used like a type.

Ah okay. :slight_smile: In the back of my mind I was wondering if I got that wrong. Now I know lol.

Yep, generics have to be resolvable at compile time.

1 Like