Just being curious - can one access (Property)Attributes at runtime without reflection?

Hi,

So this is mostly just me being curious, but something I recently realized is how often code like this occurs:

SomeScript script;

void Awake(){
    script = GetComponent<SomeScript>();
}

So I started wondering: Could we use Attributes to make this a bit less boilerplatey, perhaps like so:

[FindOnAwake] SomeScript script;

Now creating the Attribute isn’t the problem, and you could even inherit from a special base class that uses reflection in it’s Awake() method, but that’s just ugly and really not worth it.

Now I’m curious if there is any way that the attributed properties are accessible, or to have it execute code somehow. I’m expecting the answer to be a resounding “no”, but hey, who knows! :wink:

Thanks in advance,
Patrick

I also searched for a better solution one day.
But all I found was based on reflection.

So probably: No.
(However: the reflection needed for this should work on all platforms)

Without reflection, no.

And I agree, doing the finding during awake seems ugly and annoying.

What I do is I have a ‘DefaultFromSelf’ attribute:

    /// <summary>
    /// While in the editor, if the value is ever null, an attempt is made to get the value from self. You will still
    /// have to initialize the value on Awake if null. The cost of doing it automatically is too high for all components
    /// to test themselves for this attribute.
    /// </summary>
    [System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = false)]
    public class DefaultFromSelfAttribute : PropertyModifierAttribute
    {
        public bool UseEntity = false;
    }

And this special PropertyDrawer:

(note it hooks into my special PropertyDrawer events implemented through PropertyModifier… but really, the jist of the idea is what I’m shooting for showing you here)

In it I basically just grab the reference based on the type of the field during the inspector draw, if the field is empty. This way when you add a script to a GameObject it tries to grab from itself. Otherwise, you can just configure it yourself.

Then you can just be like:

[SerializeField()]
[DefaultFromSelf()]
private SomeScript _script;

Sure, it uses reflection, but not at runtime. Rather instead at editor time.

True, that’s something at least. :wink:

@lordofduct Thanks for sharing! It’s getting close, though (unless I’m mistaken) this would only work for objects who’ve had their Inspector shown, plus you’d need to Serialize every field. I agree it’s better to do it in the Editor than at runtime though, but it kind of nullifies the idea of not needing to fill you Awake() with GetComponent()s.

Just a thought: Is there any way to turn an Attributed field into a property? I.e.:

[FindOnNull] SomeScript script;

into

SomeScript _script;
SomeScript script {
    get{
        if(_script == null)
            _script = GetComponent<SomeScript>();
        return _script;
    }
    set{
        _script = value;
    }
}

It’s not quite the same, but would expect it to be “good enough” for most cases. Then again, that is an extra if-statement, so again, probably not worth it… It’s fun to think about though. Hmm…

The issue I see with that option isn’t that it’s an extra if statement… but that if the component doesn’t exist, or has been destroyed, every time you access it you’re calling ‘GetComponent’.

1 Like