- Home /
How to get every public variables(Including Buit-in) from a script in c#
Hi , I began the creation of an editor script but I fail at catching the variables of the components I look at.
Here is the code I use for my attempts: (this is a runtime code , Ill eventually have to do this in editor but lets just fix the catching variables issue first.)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System;
public class ScriptSetter : MonoBehaviour
{
public bool test;
public int test2;
public float[] floatTests;
void Start ()
{
Component[] myComponents = GetComponents(typeof(Component));
foreach (Component myComp in myComponents)
{
Type myObjectType = myComp.GetType();
FieldInfo[] fields = myObjectType.GetFields(BindingFlags.GetField | BindingFlags.GetProperty);
Debug.Log("Component --> " + myObjectType);
foreach (FieldInfo field in fields)
{
if (field != null)
{
Debug.Log("Variable --> " + field.Name + " " + field.GetValue(myComp));
}
}
}
}
}
Interestingly these few lines kind of work as they output all of the components on the object its attached to but WILL NOT return any variables :(
By Playing with the BindingFlags I havent been able to display any variables :( and by using GetField() with no parameters I could return the public variables of my own script (test variables..) with the camera public FUNCTIONS but not its variables for some reasons.
My GOAL is to return every variables THAT ARE DISPLAYED IN THE INSPECTOR. Then for a bonus question , I would be able to know the current value of the variable and its limitations (ex: the attribute [range(0,10)] for a float).
Thx in advance.
NOTE After more investigation Im realising that this is possibly working but only with the user made scrips and not the actual unity components such as the camera. In other words I get no fields from the Build in classes :(
I'm assu$$anonymous$$g your trying to interrogate your objects at runtime (this works in either editor run time or standalone), and need some decent debug watch capacity... if your not using visual studio by now for unity program$$anonymous$$g, shift over to it. nothing has the power of VS for making code
and, then you can read through this
https://msdn.microsoft.com/en-au/library/dn940020.aspx
attach visual studio to unity, which is in that msdn page, and then set some break points.. when the program lands on a line with a breakpoint, you'll be able to hover the mouse over any variable (object or primitive) and see its entire upward structure... then you'll have access to everything in those objects, and every value they currently contain
Thank you very much for the suggestion. I sadly cannot consider that option for now as I am working on an asset to put in the store and people will require the access to every public variable that gets displayed in the inspector.
Still thx again :P
Also I will modify a tad my description as THIS code is for runtime simply to test (catching variables from components) while my final goal will be to make this work in the editor script im am working on , that is not shown here.
Guessing here, but maybe thats becouse theres no script attached to the camera.
Hmm , sadly no , there are scrips as demonstrated in the screenshot.
There is a Camera GameObject and all the component in it gets detected. The only variables that get printed are the one from the custom scripts.
As you can see the Camera component appears in the console under the name : UnityEngine.Camera
Sorry, I mean there is no script in Camera component of Camera gameobject, so GetFields probably wont get any values.
This works for me
$$anonymous$$emberInfo[] memberArray = myType.Get$$anonymous$$embers();
foreach (var item in memberArray)
{
print(item.Name);
}
Hey this sounds like the best option so far !!!
Thx a bunch , the only problem I have now is that this outputs way more then only public variables BUT I will try and find a solution from there I am pretty confident.
THAN$$anonymous$$ YOU again !
Answer by Potatobob · Apr 01, 2017 at 08:19 PM
I finally did it after referring to this post : http://answers.unity3d.com/questions/754412/getting-variables-by-their-names.html
Here is the script I came up with , I hope this can be useful to someone else , I almost spent a week just on getting those variables info XD
using UnityEngine;
using System.Reflection;
using System;
public class ScriptSetter : MonoBehaviour
{
void Start()
{
Component[] myComponents = GetComponents(typeof(Component));
foreach (Component myComp in myComponents)
{
Type myObjectType = myComp.GetType();
foreach (var thisVar in myComp.GetType().GetProperties())
{
try
{
Debug.Log("Component: " + myComp.name + " Var Name: " + thisVar.Name + " Type: " + thisVar.PropertyType + " Value: " + thisVar.GetValue(myComp,null) + "\n" );
}
catch (Exception e)
{
Debug.LogError(e);
}
}
}
}
}
In short :
List the component of an object
List the variables of those components
Debug the result and additional information.
Edit : I just removed 19 lines from that script , we get the same result but with much less work. Thx to MadKnight from CodingGame
There is a lot wrong or overcomplicated in that script.
First of all GetComponents already returns the references to the actual instances. Getting the class name from the instance and using it again in GetComponent makes no sense. You should directly use the references in your myComponents array.
You do the same thing with the PropertyInfos. PropertyInfo is derived from $$anonymous$$emberInfo. When the $$anonymous$$emberType is "Property" the "item" is a PropertyInfo. So no need to use GetProperty again.
Next thing is "properties" are not "variables". Properties are just ordinary "methods".
Built-in components don't have any variables (fields) in their managed classes since the actual variables are stored in the native code counter part. Those variables can only be accessed through properties. Custom classes on the other hand do have actual fields.
"$$anonymous$$emberType" is an enum so converting it into a string and comparing the string is just a waste of performance and not type safe.
Finally as others have already said which fields are serialized and therefore show up in the inspector depends on many other factors, mainly the attributes of the fields. However built-in components are completely special. First you can't deter$$anonymous$$e which variables are actually serialized as they are defined in native code. Second most built-in components have specialized custom inspectors which might not show certain variables which are actually serialized.
The whole inspector and serialization system of Unity uses the SerializedObject / SerializedProperty wrapper system. The only reliable way to access and view all serialized fields is to use the SerializedObject class. Of course it can only be used in an editor script but your original question said it's about an editor script.
Just judging by the amount of different answers and comments it seems your question isn't really clear what your actual goal is (what's the purpose?)
Hi there ! Thx a bunch for your answer :P
First of , English is not my main language so I do get confused with some terms and I also learnt C# on my own so there are holes in my knowledge.
This being said I do not understand all what you are telling me :( But it does sounds right XD
Also , I just noticed (23hours after your post , your answer but I did edit that script since yesterday night to make it more efficient.)
Now for the answer to : < GetComponents already returns the references to the actual instances.> I tough in first place that the first check would return the component type and not an actual instance but did realized that mistake later on ! (Thx anyway :P)
< "properties" are not "variables". Properties are just ordinary "methods"> This is probably what confused me the most , and this is why I realized today that this code STILL does not even pull out all the variables and that is the main reason to it. (Thank you)
I added the Build-In term to my issue as I Had a lack of knowledge and tough that perhaps this was why I could not see the UnityEngine.Component variables... (Im definitively gonna stay as far as possible from the Built-In complicated stuff , I want only the basic and public variables like a simple bool that you get and set.)
I am right now modifying my script once again as it used to return the PROPERTIES but not the variables and it seems like I need some of both... Ill definitively give a good look at Serialized stuff as I have no clue what this means right now.
< what your actual goal is (what's the purpose?) > Lets keep that answer as clear as possible while keeping it simple: I need to get a list of all variables that are displayed in the inspector so I can modify them afterwards. This must work in Editor AND I should be able to modify EVERYTHING that the user normally see in the inspector when selecting a component.
When I can achieve that I will be able to implement another code I have that iterate through every possibility of combinations (And no this is not just 3 for loops unless I REALLY SUC$$anonymous$$ in coding)
So the asset would basically let you pull out any object and decide a way to iterate through the variables , it will then generate a specific amount of instances of that object with the given variables on the given components.
Can't be more clear unless I make a drawing I guess.
Anyway thx for your GREAT feedback , Ill go back in the code and see if serialization actually work of If I should keep going with my 2 iterations 1 for properties and 1 for fields THEN filter out every variables that aint showing in inspector.
O$$anonymous$$G. After 3 years nobody will not read this, but... I`m tried use your code and it give me info about all standart components like Rigidbody, Transform, etc. but... I didn`t see any variables from my scripts. Why? What changed after 3 years? )
Answer by JHobsie · Apr 01, 2017 at 02:05 AM
Edit: I just did a quick play with SerialisedObject and you can loop through all SerializedProperties.
Camera c = GetComponent<Camera>();
SerializedObject serObj = new SerializedObject(c);
SerializedProperty prop = serObj.GetIterator();
while (prop.NextVisible(true))
{
Debug.Log(prop.name);
}
I think this is much closer to what you want over using type.GetProperties/GetMethod! Works only in the Editor.
-----------
Most inbuilt behaviors are done differently than our own custom behaviors with lots of internal stuff and native code. For example in Camera.cs there is no clearFlags variables, only a property
public extern CameraClearFlags clearFlags
{
[MethodImpl(MethodImplOptions.InternalCall)]
get;
[MethodImpl(MethodImplOptions.InternalCall)]
set;
}
However, most or all? Variables displayed in the inspector generally have a Property associated with it (just like clearFlags above), so you could use
t.GetProperties(BindingFlags.Instance | BindingFlags.Public);
This returns way more than just the inspector fields though, I'm unsure how you'd be able to filter through them in a generic way that works for all behaviors. I will play around with SerializedObject and see if there is any way to do it through that.
Also, you said you want to display all inspector fields of a component. Just getting public variables will not work if the field is private with the attribute
[SerializeField]
int bob = 1;
In order to get all of these fields as well, you will have to get all fields, including private ones and check if this attrbute is defined. You will also need to check if the System.NonSerializedAttribute is not defined.
You can check if an attribute is defined via the IsDefined method.
FieldInfo fi;
fi.IsDefined(typeof(SerializeField));
Great answer , I sadly don't achieve my goals with this either.
Let me explain: I have transferred the code in a Editor script ins$$anonymous$$d and can now pull out the variable names in a different way.
Thing is for the Transform component (by example) is separated in x , y and z ins$$anonymous$$d of being presented as a vector3 which would normally be called position..
This causes me big issues when comes the time to display the variables to the user as they don't look like their original.
Finally I still have to get the value of those variables. I feel like I also have to convert the variable names from string to actual variables in order to get their value.
Here is the code I have right now:
Editor: using UnityEngine; using UnityEditor;
[CustomEditor(typeof(ScriptSetter))]
public class CustomScriptSetter : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
ScriptSetter myScript = (ScriptSetter)target;
if(GUILayout.Button("GetList"))
{
Component[] myComponents = myScript.gameObject.GetComponents(typeof(Component));
foreach (Component myComp in myComponents)
{
SerializedObject serObj = new SerializedObject(myComp);
SerializedProperty serProp = serObj.GetIterator();
while (serProp.NextVisible(true))
{
if (serProp.type == "int" || serProp.type == "float" || serProp.type == "bool")
{
Debug.Log(serProp.name + " " + serProp.type);
}
}
}
}
}
}
and here is the normal script
using UnityEngine;
using System.Reflection;
using System;
public class ScriptSetter : $$anonymous$$onoBehaviour
{
void Start()
{
Component[] myComponents = GetComponents(typeof(Component));
foreach (Component myComp in myComponents)
{
Type myObjectType = myComp.GetType();
$$anonymous$$emberInfo[] memberArray = myObjectType.Get$$anonymous$$embers();
foreach (var item in memberArray)
{
//this if is to look only at variables and forget about methods and constructors...
if (item.$$anonymous$$emberType.ToString() == "Property")
{
Debug.Log(myComp + " " + item.Name + " ");
}
}
}
}
}
Yes both code give me variables but they both have their flaws apparently and I feel like I am almost back to square one /cry
Answer by grykrzysztof · Mar 30, 2017 at 04:03 PM
Try this:
fieldInfo = myType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
Thx for your answer sadly this is not providing me all the variables I am looking for , maybe the one I am missing are protected in some way. (updated the description)
Note the exact same answer is valid for Positive7 as both of your answer gave me the same result.
Answer by Positive7 · Mar 30, 2017 at 09:06 AM
var fields = myObjectType.GetFields(BindingFlags.Instance | BindingFlags.Public);