Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

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

Discussion in 'Scripting' started by Senshi, Oct 30, 2015.

  1. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    552
    Hi,

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

    Code (CSharp):
    1. SomeScript script;
    2.  
    3. void Awake(){
    4.     script = GetComponent<SomeScript>();
    5. }
    So I started wondering: Could we use Attributes to make this a bit less boilerplatey, perhaps like so:

    Code (CSharp):
    1. [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! ;)

    Thanks in advance,
    Patrick
     
  2. sz-Bit-Barons

    sz-Bit-Barons

    Joined:
    Nov 12, 2013
    Posts:
    150
    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)
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,375
    Without reflection, no.

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

    What I do is I have a 'DefaultFromSelf' attribute:
    Code (csharp):
    1.  
    2.     /// <summary>
    3.     /// While in the editor, if the value is ever null, an attempt is made to get the value from self. You will still
    4.     /// have to initialize the value on Awake if null. The cost of doing it automatically is too high for all components
    5.     /// to test themselves for this attribute.
    6.     /// </summary>
    7.     [System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = false)]
    8.     public class DefaultFromSelfAttribute : PropertyModifierAttribute
    9.     {
    10.         public bool UseEntity = false;
    11.     }
    12.  
    https://github.com/lordofduct/space...b/master/SpacepuppyBase/PropertyAttributes.cs

    And this special PropertyDrawer:
    https://github.com/lordofduct/space...tor/Base/Modifiers/DefaultFromSelfModifier.cs
    (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:
    Code (csharp):
    1.  
    2. [SerializeField()]
    3. [DefaultFromSelf()]
    4. private SomeScript _script;
    5.  
    Sure, it uses reflection, but not at runtime. Rather instead at editor time.
     
  4. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    552
    True, that's something at least. ;)

    @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.:

    Code (csharp):
    1. [FindOnNull] SomeScript script;
    into
    Code (csharp):
    1. SomeScript _script;
    2. SomeScript script {
    3.     get{
    4.         if(_script == null)
    5.             _script = GetComponent<SomeScript>();
    6.         return _script;
    7.     }
    8.     set{
    9.         _script = value;
    10.     }
    11. }
    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...
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,375
    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'.
     
    Senshi likes this.