3
Type thistype = stringVar.GetType();
thistype myScript = gameObject.AddComponent(stringVar);

myScript.runCustomFunction();

This doesn't work, and I believe it is because I cannot cast to a variable type if I don't know the variable type at compile time (rather than run), therefore I am unable to directly access the component I just added.

I have a gameItem class which pulls its default values from another script, then puts them into a dictionary. Based on the dictionary entry "functionScript","myScript", I need to attach myScript to the object, then pass it some dictionary entries.

Alternatively, I could be really inefficient and ask the item class for its variables on the myScript class, which I'd rather avoid.

user3071284
  • 6,955
  • 6
  • 43
  • 57
  • 1
    Ok, so I'm having trouble understanding *exactly* what you are trying to accomplish. The value of `stringVar` is something like `"myScript"` and you need to be able to pull in the appropriate concrete type based on the name? – Josh Jul 31 '13 at 11:54
  • the string stringVar is equal to "myScript" (or any other script name, dependant on the string passed by the default item value setting). I need to use that string to add a component script called myScript (or any other name, whatever is passed), then run a function/pass some variables to the newly added component. – DigitalSalmon Jul 31 '13 at 12:06
  • 1
    But does that value correspond to a concrete Type? You obviously know something about it or you wouldn't be trying to call `runCustomFunction` on it. Do all your types inherit from the same underlying base class? Or implement an interface? – Josh Jul 31 '13 at 12:08
  • Thank you for your speedy replies! - I'll try to clarify what I'm attempting to do: I have a gameItem class, which stores all sorts of variables (item type, damage, cooldowns etc etc). If manual override is turned off, I run a function to set all the default values on the gameItem class (pulling from a dictionary). One variable is a string called gameItemScript. When the method AddWeaponScript(string gameItemScript) is called it needs to add the component called gameItemScript, then set some variables on that component. – DigitalSalmon Jul 31 '13 at 12:16

1 Answers1

1

System.Type is an actual type, much the same as System.Int32, or System.Guid. You can't use a variable as a static identifier in your code since the compiler has no idea what that type is.

I think what you are trying to do is construct a concrete type based on its name.

You can use Activator.CreateInstance to do this, so long as you know the type name and assembly name.

var typeName = "MyType";
var myType = Activator.CreateInstance("MyAssembly", typeName); 

You could also use the dynamic keyword to let the DLR handle the heavy lifting for you.

dynamic myType = Activator.CreateInstance("MyAssembly", typeName);
myType.runCustomFunction();

If your type inherits from a common base type, or implements an interface, you can then cast it to that type and call your method.

//Safe cast as base type
var myType = Activator.CreateInstance("MyAssembly", typeName) as BaseType;

//Or safe cast as interface
var myType = Activator.CreateInstance("MyAssembly", typeName) as IMyType;

However, if your types do not inherit from a known type, but you know they all have a method called runCustomFunction and you don't want to use dynamic then you can use a little reflection to invoke that method.

//Create the System.Type using assembly qualified name
var typeName = "MyType";
var assemblyQualifiedName = String.Format("MyAssembly.{0}", typeName);
var myType = Type.GetType(assemblyQualifiedName);

//Call activator overload, but `instance` is a System.Object
var instance = Activator.CreateInstance(myType);

//Use reflection to invoke the method
myType.InvokeMember(
   "runCustomFunction", //member name
   BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static,
   null, //default binder
   instance, //actual instance to invoke method on
   null //no arguments so we use null
);

As you can see, it's much easier to just make all your types inherit from some base class or implement an interface, but you can certainly use reflection if you want to do it the hard way :)

Josh
  • 44,706
  • 7
  • 102
  • 124
  • Massive props for taking the time to cover all the possibilities. I'm doing my best to find answers on my own, however - In this situation, what does "MyAssembly" represent? – DigitalSalmon Jul 31 '13 at 12:35
  • @DS I also added the `dynamic` option to the list. Almost forgot about that. In this case `MyAssembly` represents the name of the assembly the type is defined in. Typically this is the same as your project name, but you can check the properties to be sure. For instance if my project was named `JoshStuff` then my assembly name is more than likely going to be the same. – Josh Jul 31 '13 at 12:39
  • For future reference - It would appear the Assembly reference for Unity3d is "Assembly-CSharp". `var typeName = scriptName;` `var myType = Activator.CreateInstance("Assembly-CSharp",typeName);` `myType itemScript = gameObject.AddComponent(scriptName);` That code returns "The type or namespace name `myType' could not be found. Are you missing a using directive or an assembly reference?" – DigitalSalmon Jul 31 '13 at 12:49
  • @DigitalSalmon Is this a custom type that you created? One that sits in your project? – Josh Jul 31 '13 at 12:54
  • I'm not sure I fully understand the principal of types in this situation. Normally the "Type" is just the script name if you are adding a script component to an object. By that logic, yes, the Type is a custom type. – DigitalSalmon Jul 31 '13 at 13:10