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);
    }

173669-console1.png


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.

173670-console2.png


I’ll be very grateful by any help anyone can provide.

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.

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*;*

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;
}