As others have already pointed out what you’re doing here just doesn’t make sense. I think one issue here is that you did not clearly explain what you want to do. One part of the issue is the usage of vague terminology like “script”. The term “script” does not really exist in C#. Within Unity the term specifically refers to a C# file that contains a MonoBehaviour derived class. This combination of file and class (which have to have the same name) is called a Script in Unity. Those can be attached to gameobjects.
Of course you don’t talk about “those” scripts since you have ordinary classes that are not derived from MonoBehaviour and you want to create them manually by using the constructor. In C# there’s the concept of types and objects (or instances of types). Those are two very different things. Variables or parameters of methods (which are also variables) do have a type and would need to contain an actual value / instance of that type. You can not directly pass a “type” in a variable.
C# has the concept of generic types and generic methods which allow to specify a “type argument”. However generic type arguments are not variables. Generic arguments allow the CLI to late bind an actual type at runtime and may produce specialized types or versions based on the used type. It is possible to create a generic method where you can specify a certain type and have the method create an instance of that type. For this the generic argument needs to have the “new” constraint which would require the type to provide a parameterless constructor. It does not work with a constructor that takes any parameters.
public void EquipItem<TItem>() where T : IEquipable, new()
{
listOfEquippedItems.Add(new T());
}
This would be possible, though as I just mentioned, it only works with a parameterless constructor. Your interface may include some sort of Init method that could be called after it has been created. To call this method you would do
EquipItem<Helmet>();
However as I said, Helmet
in this case is not and can not be a variable. This is just a generic method that can be used with different types. It’s like creating separate methods for each type, just that you don’t have to create them manually.
What you may have in mind is somehow pass a “type” to the method of the object that should be created and added. This is possible in C#. though not that way you want it to work. This is only possible by using the reflection system of C# / .NET. The CLI of .NET has a type system that includes a special type called “System.Type”. This class is used to “describe” any type within the CLI. This is part of the reflection system and every type has a System.Type object. You can get that object by using the “typeof” operator System.Type itemType = typeof(Helment);
or when you have an instance of a type you can use the GetType()
method that every type has. This includes even primitive types such as integers or strings.
var t1 = typeof(string);
var t2 = "Hello World!".GetType();
t1
and t2
would both contain the System.Type object that describes the System.String type.
With the System.Type object of a type you can do all sorts of things, including creating an instance of that type. This has to be done either through the System.Activator class, or by getting a ConstructorInfo instance of that class and invoke that. The Activator class simplifies the usage as it tries to find the “best” constructor that fits your parameter list.
Note that using reflection is kinda slow and you can easily mess things up. So type incompatibility issues will only show up at runtime when you try to execute it. You also need to cast the created instances to your desired type.
Unity itself uses reflection for adding components to gameobjects. The AddComponent method takes a System.Type object to specify which type should should be used to create a new instance that will be attached to a gameobject. The generic version of AddComponent is just a shortcut for
public T AddComponent<T>()
{
return AddComponent(typeof(T)) as T;
}
So Unity instantiates the actual component on the native C++ side based on the passed System.Type object.
Maybe you’re looking for something like that as well? Though I would say it’s a bad design that an equipable object requires the wearer as an argument in the constructor. That means those objects can not exist unequipped since you can not create one without a wearer. It would make much more sense to have an Equip / Unequip method in that interface. Here you would pass the wearer as argument to the Equip method. Usually instances of equipable items may be used at other places as well, like placing them in an inventory or dropping it into the world or something like that. The “IEquipable” interface would only be the part that is relevant for an object that can be equipped. Though equipable items may have other uses as well.