AddComponent Based On String (Or Alternative) [SOLVED]

So, I have a string name “Item”. Which is also the name of a script component I would like to add, but I am having some trouble. Basically, my script now is

Public string ScriptToLoad;

ScriptToLoad = PlayerPrefs.GetString(ItemName);
gameObject.AddComponent(ScriptToLoad);

This script kinda gets string names from different sources and the AddComponent bit basically needs to be able to change the name of the script.

However, I cannot get it to work as it tells me AddComponent with string argument has been deprecated.
Alright, so, what do I need to do to get this to work is my question? :slight_smile:

1 Like

no guarantees but you could try typeof

//at the top of your script
using System;

gameObject.AddComponent(typeof(ScriptToLoad));

Typeof doesn’t actually take a string, it’s used to obtain they System.Type object for a specified Type.

To get a System.Type object from a string use Type.GetType.

3 Likes

Thanks.
That gets me one step closer but I don’t think I quite understand or get the execution of how that’d look?

gameObject.AddComponent(Type.GetType(ScriptToLoad));

Like so?

Hmmmm. Well, the intent is to save and load a component to a gameobject.
So that when it loads, it knows what component it should load. Just not sure I am going about that the right way.

my bad, got it backwards

Have you tried it out? Did it work?

Sadly, no

Still stuck, I’m affraid

I misspoke, I forgot to add

using System;

Well then! :slight_smile:
Thanks!

I wouldn’t rely on that, you’re already using reflection every time you need to do that. If you’re going to go down that route, consider doing this:

[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]
public class ComponentIdentifierAttribute : Attribute
{
    public string Name {get; set;}
}

Then on your class:

[ComponentIdentifierAttribute(Name = "Item")]
public class SomeComponent : Monobehaviour
{
...
}

Then, when your game initializes build a cache…

public static class ComponentCache
{
    public static Dictionary<string, Type> Registrations = new Dictionary<string, Type>();
}

And in your initialization code

foreach(var assembly in AppDomain.Currentdomain.GetAssemblies())
{
     foreach(var currentType in assembly.GetTypes().Where(_ => typeof(MonoBehaviour).IsAssignableFrom(_))
     {
           var attributes = currentType.GetCustomAttributes(typeof(ComponentIdentifierAttribute), false);
           if(attributes.Length > 0)
          {
                var targetAttribute = attributes.First() as ComponentIdentifierAttribute;
               ComponentCache.Registrations.Add(targetAttribute.Name, currentType);
          }
     }
}

Code above was for brevity… you’ll obviously want to check to make sure registrations aren’t done more than once or it will throw an exception. But now, you can do this:

var typeToLoad = ComponentCache.Registrations[ScriptToLoad];
gameObject.AddComponent(typeToLoad);

The above code is all for demonstration… it lacks error checking and may have some typos or scenarios I didn’t think about, but it’s mean to give you the general idea. You actually wouldn’t even need to use reflection at all if you just manually registered your component types in your setup rather than getting them from attributes, but this takes the extra reflection work out of your add component piece.

2 Likes

Is reflection really that slow to worry about it? I get if you are doing it multiple times per frame. But for the occasional load/save a registration system seems to be overkill. The AddComponent call is likely to be more costly then the reflection call.

Yes and no… and GetType isn’t terrible because it’s metadata. So it’s not bad at all. The problem is that, if you’re not fully qualifying the type name and you have the same type specified in more than one namespace there could be an issue. Also, the registration system allows you to rename classes or even move them to different assemblies without breaking the implementation, though I’m not a fan of the magic string approach anyway.

You could also use Enums instead of strings to make your registrations more strongly typed, and it’s easier to debug because if it can’t find something, you can always use the debugger to look at the list of registrations to see if something is simply a typo or really is missing.

1 Like