- Home /
How can you find private fields by reflection inside a Property Drawer?
I'm building an open source asset to add some attributes, as the ones available (Naughty Attributes and Unity Editor Toolbox) didn't cover all my needs.
I'm currently working on a [ShowIf]
attribute and its variants and I'm making my life harder by considering non-serialized values as in:
[SerializeField] [ShowIf(nameof(_teste2))]
private bool _test1;
private bool _teste2;
I can access the fields of a object if I initialize it with a given type:
System.Object obj = new PlayerController();
var fields = HelperMethods.GetAllFields(obj, f => f.IsPrivate);
foreach (var item in fields)
{
print(item);
}
But I can't do the same inside the drawer, as I can't initialize it with predefined class, even with the knowledge I gained looking here and here.
var comparisonAttribute = attribute as ConditionalAttribute;
System.Object propertyObj = HelperMethods.GetTargetObjectOfProperty(property);
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
var fields = propertyObj.GetType().GetFields(flags);
Debug.Log(propertyObj);
foreach (var item in fields)
{
Debug.Log(item);
}
Debug.Log(fields.Length);
All I'm getting now is the type, where I can only access the property's field, as the console print can show.
I'll be very grateful by any help anyone can provide.
Answer by MSavioti · Jan 06, 2021 at 04:42 AM
This is how I got it working:
System.Object objectInstance = property.GetTargetObjectWithProperty();
//This is my attribute class
var comparisonAttribute = attribute as ConditionalAttribute;
// Don't forget to use BindingFlags
FieldInfo field = objectInstance.GetField(comparisonAttribute.PropertyName);
PropertyInfo hiddenProperty = objectInstance.GetProperty(comparisonAttribute.PropertyName);
// Author: github.com/lordofduct
/// <summary>
/// Gets the object that the property is a member of
/// </summary>
/// <param name="self"></param>
/// <returns></returns>
public static object GetTargetObjectWithProperty(this SerializedProperty self)
{
string path = self.propertyPath.Replace(".Array.data[", "[");
object obj = self.serializedObject.targetObject;
string[] elements = path.Split('.');
for (int i = 0; i < elements.Length - 1; i++)
{
string element = elements[i];
if (element.Contains("["))
{
string elementName = element.Substring(0, element.IndexOf("["));
int index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
obj = HelperMethods.GetValue_Imp(obj, elementName, index);
}
else
{
obj = HelperMethods.GetValue_Imp(obj, element);
}
}
return obj;
}
Answer by Bunny83 · Jan 05, 2021 at 11:47 PM
Well, if you have the FieldInfo you can simply call GetValue on that fieldInfo. You need to pass the actual object that this field belongs to as parameter to GetValue, so in your case your "propertyObj". Any instance field of course needs the actual instance reference to read or write that instance's value. Only static fields do not need an instance.
Thanks for the response @Bunny83 ! I feel I'm a little closer to the expected result, but I'm having trouble in getting the Instance value which you spoke about. Here's my updated code with GetValue( )
added:
System.Object propertyObj = Helper$$anonymous$$ethods.GetTargetObjectOfProperty(property);
System.Type type;
FieldInfo propertyFieldInfo = property.GetFieldInfoAndStaticType(out type);
System.Object obj = propertyFieldInfo.GetValue(propertyObj);
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
var fields = obj.GetType().GetFields(flags);
But I'm getting the following error:
Can you please help me in this as well?
Your answer
![](https://koobas.hobune.stream/wayback/20220613022742im_/https://answers.unity.com/themes/thub/images/avi.jpg)