- Home /
Converting a string into a type, then using that type in a script.
So to begin with, I'm writing an editor script that serves the following purpose: It will be able to access any MonoBehaviour (user defined) and access any list on that MonoBehaviour (again user defined), and will then display this list in a user friendly manner.
The script looks a little bit like this:
public class ListOrganizer : EditorWindow
{
System.Type targetType;//This is the type that we are using in our list
public System.Collections.Generic.List<Resource> list =
new System.Collections.Generic.List<Resource>();
public Resource classType = new Resource();
FieldInfo[] fieldInfos;
public ShipController sourceScript;//This is the script with the list we will be editing
public string listName = "Target List Name";//This is the name of the list variable that we want to edit
bool editing = false;
[MenuItem("Window/ListOrganizer")]
public static void Init()
{
ListOrganizer listOrganizer = (ListOrganizer)EditorWindow.GetWindow(typeof(ListOrganizer));
}
void OnGUI()
{
if(!editing)
{
sourceScript = EditorGUILayout.ObjectField(sourceScript, typeof(ShipController), true) as ShipController;
listName = EditorGUILayout.TextField(listName);
if(GUILayout.Button("Start Editing"))
{
Debug.Log(listName);
if(sourceScript != null)
{
list = (System.Collections.Generic.List<Resource>)sourceScript.GetType().GetField(listName).GetValue(sourceScript);
editing = true;
}
}
}
if(editing)
{
...//Display all the editing information
}
}
Apart from one major error, it's working really well. However, currently this code only works for displaying List*Resource*
types and only from the MonoBehaviour ShipController. What changes do I have to make so that I can grab List*ANYTYPE*
from MonoBehaviour [ANYSCRIPT]?
Everything I've been able to find points me to something like what is described here. http://answers.unity3d.com/questions/42498/how-do-i-convert-a-string-into-a-class-reference-i.html
So what I would want is something like System.Type targetType = typeAsAString.GetType().
But then how do I get the type based an a string, then utilize that type throughout the rest of this script?
NOTE: Not sure why but I can't use "<" and ">". Edited to clear up the confusion.
I know it's been 2 years, but did you find out a solution? If so, how?
Answer by Kiwasi · Oct 13, 2014 at 07:47 AM
I'm not sure what you are after. Are you looking for this?
System.Type myType = Type.GetType(SomeClass);
To clarify, right now this script can only access a list of type Resource in the $$anonymous$$onoBehaviour ShipController. I want the user to be able to enter in a string ("SomeOtherClass") and another string ("Some$$anonymous$$onoBehaviour) and be able it access list of type SomeOtherClass in Some$$anonymous$$onoBehaviour. Then I can get the FeildInfo from this class and edit their fields in the inspector.
I am aware that I need to utilize that function in some form. But how can I I later edit variables that use myType as a type?
For example:
String someString = "UserDefinedString";
System.Type myType = someString.GetType();
myType someVariable = new myType();
System.Collections.Generic.List<myType> myList;
myList.Add(someVariable);
Answer by jctz · Oct 13, 2014 at 09:36 PM
I believe you're looking for Activator.CreateInstance:
System.Type UserDefinedType = Type.GetType("UserDefinedClassString");
object myTypeInstance = Activator.CreateInstance(UserDefinedType, {constructor params});
When attempting this method, I get the error: "A field initializer cannot reference the non-static field, method, or property 'ListOrganizer.UserDefinedType'" I am attempting to use the default constructor and my code looks almost identical to what you have written.
Do I need to make a class called UserDefinedType? or does it need to be a static variable? I have never used Activator.CreateInstance(), so I am not sure what is required.
So, after changing the line to public static System.Type UserDefinedType
, it seems that the Activator works properly. However, when later attempting to use the instance I get this error "myTypeInstance is a 'field' but is used like a 'type".
To add to my previous comment, how do I get it to behave as a type after it has been user-defined?
Answer by Bunny83 · Oct 14, 2014 at 01:47 AM
I think you try to create a "general purpose editor" which actually doesn't make much sense. In Unity we only have compiled languages with strong typing of variables. According to OOP and inheritance you can generalize a reference, but then you loose the access to any specific properties. For example, you could change your ObjectField to allow any of your script instances to be selected by replacing typeof(ShipController) with typeof(MonoBehaviour). Now the returned value can't be casted to ShipController since it's now just a MonoBehaviour and all things specific to a certain class like your ShipController class can't be accessed. Only things available in the base class which is MonoBehaviour in my example.
You can however use reflection to access dynamically any type of class / class member, but you have to use reflection for everything in this case. Something similar to this has already been done in Unity: The serialization system. This is a huge framework and only supports some basic types.
I've once made a very (very) simple inspector window which works at runtime in my Android build. I could select and object in the scene, browse through it's components, see it's fields / properties / methods and could view / edit a few types (int, string, float) and could call parameterless methods. This was already a quite huge framework and a lot of work.
If you really want to implement something like that, you should get familiar with the whole reflection namespace and how the System.Type object works.
Like others said it's hard to understand what exactly you want to do. What does "access" mean to you? What's the purpose of that window anyways? The InspectorWindow does most of those things already. Maybe you just want to create some CustomEditors or PropertyDrawers to modify the view of the Inspector? Creating an inspector from scratch would be crazy.
You can however use reflection to access dynamically any type of class / class member, but you have to use reflection for everything in this case. Something similar to this has already been done in Unity: The serialization system. This is a huge framework and only supports some basic types.
Yes. This is my goal. I'm not trying to create a whole new inspector, just organize the way that Serialize Classes can be edited. The script I've written currently utilizes Reflection as you have described. It is able to grab variables of all kinds, but only from the classes that I script in. In the script that I have made, I want to be able to replace Resource with UserDefinedType and replace ShipController with UserDefinedScript. If this is not possible, then that's fine, I'll just move on. But if it is, I would like to know how.
The whole purpose is to create a more developer friendly interface, because the unity way of working with serialized data list is attrocious. $$anonymous$$aybe what I want IS just a custom Editor for this. I don't feel like it is, but maybe. I haven't worked with the custom editor interface very much, so maybe I went about this in the wrong manner.
$$anonymous$$y way looks like this:
I suppose the most important question is this. Is it possible to make this work for ANY list? That is my goal: To have the above view screen, which only works for lists that I tell it to work for, work for (almost) any list.
Answer by MagyarPeter · Oct 10, 2021 at 01:47 PM
IMPORTANT: write "using System;" to the top of the script, this is necessary because it NOT WORKS with "System.Type" for some reason!
Type stringToType(string from)
{
return Type.GetType(from);
}
Get the type string of a script: //(type "using System;" to the top) string typeToString(Type from) { return from.FullName; }