Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
4
Question by spectre1989 · Aug 27, 2013 at 02:15 PM · nullunityengine.object

Testing for null, bug or feature?

Hi there,

I've noticed that if I have an object which inherits from UnityEngine.Object, and it gets destroyed and so becomes null, the following happens:

 Debug.Log( myObject ); // Outputs "null"
 
 if( myObject == null )
 {
    // This code doesn't run?
 }
 
 if( !myObject )
 {
    // But this code does
 }

So testing for null explicitly doesn't work, presumably this is because there is actually an object there, but it has to behave as if it is null.

Now, I don't like using the if( !myObject ) test, I think it's bad practice. Even so, for the particular code I'm writing now I actually can't use that, as I'm working with System.Object instances which may or may not also be UnityEngine.Object instances.

So, is this a bug, or a feature?

Edit: This code will very quickly show the problem I'm talking about:

 using UnityEngine;
 
 public class NewBehaviourScript : MonoBehaviour 
 {
     private System.Object go;
     private System.Object t;
 
     public void Start()
     {
         GameObject temp = new GameObject( "go" );
         this.go = temp;
         this.t = temp.transform;
 
         Destroy( temp );
     }
 
     public void Update()
     {
         Debug.Log( this.go == null );
         Debug.Log( this.t == null );
     }
 }
 
Comment
Add comment · Show 4
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image sdgd · Aug 27, 2013 at 02:21 PM 0
Share

yes it's exactly like your code says

     if( myObject == null )
     {
     // This code doesn't run?
     }
      
     if( !myObject )
     {
     // But this code does
     }
     if (myObject == false){
         // this code will run even if object is null
     }

and yes it's a feature you aren't checking if the object exists but you are trying to use the object

so giving ! before object is simply asking if it's not true and not asking if it's not null

avatar image spectre1989 sdgd · Aug 27, 2013 at 02:35 PM 0
Share

That doesn't make sense, ! before the object is short hand for a null check.

avatar image robhuhn sdgd · Aug 28, 2013 at 07:23 AM 0
Share

The implicit null check only works if the object overloads the !-operator and return a boolean value otherwise it will give a compiler error. It's not a default behavior in c# so you usually check with == , != or Equals().

avatar image aeroson · Mar 20, 2015 at 12:37 PM 0
Share

Looking at ILSpy => UnityEngine.Object implements only != , == , Equals and implicit operator bool, which is what gets called for if(obj) or if(!obj). All of those do more than just a simple null check.

2 Replies

· Add your reply
  • Sort: 
avatar image
5
Best Answer

Answer by TonyLi · Aug 27, 2013 at 05:23 PM

UnityEngine.Object overrides Equals(). The null-coalescing operator (??) also doesn't work. It's just the way Unity works. This forum thread has a deeper discussion on the issue.

Comment
Add comment · Show 7 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image spectre1989 · Aug 27, 2013 at 10:09 PM 0
Share

But if UnityEngine.Object was properly overridden then it wouldn't be a problem surely?

avatar image TonyLi · Aug 28, 2013 at 12:32 AM 1
Share

Like @Jamora wrote in @Bunny83's thread, and just as in the forum thread I linked you to, UnityEngine.Object implements the null object pattern so Destroy can work cleanly. You break the pattern by casting back to System.Object. If you have a UnityEngine.Object, you should always keep a reference as a UnityEngine.Object or descendant.

avatar image spectre1989 · Aug 28, 2013 at 09:07 AM 0
Share

System.Object.Equals is virtual, so it shouldn't matter that it's casted back to a System.Object

avatar image TonyLi · Aug 28, 2013 at 03:03 PM 0
Share

It matters if Unity never actually sets it to null. I think @Bunny83 did a good job of explaining in a comment below his answer.

avatar image spectre1989 · Aug 28, 2013 at 03:27 PM 0
Share

I understand what's been said, but still I'm pretty sure that this shouldn't happen if Equals is properly overridden as it is virtual.

Show more comments
avatar image
0

Answer by Bunny83 · Aug 27, 2013 at 02:37 PM

I can't reproduce this behaviour. Is it possible that you use Destroy and test the object reference in the same frame? The object is destroyed the next frame....

If you wait at least one frame or use DestroyImmediate it works as expected

     var GO = new GameObject("Test");
     Debug.Log("GO == null: " + (GO == null));
     Debug.Log("GO != null: " + (GO != null));
     Debug.Log("!GO: " + (!GO));
     Debug.Log("GO == false: " + (GO == false));
     Debug.Log("GO != false: " + (GO != false));
     GameObject.Destroy(GO);
     yield return null;
     Debug.Log("Destroy");
     Debug.Log("GO == null: " + (GO == null));
     Debug.Log("GO != null: " + (GO != null));
     Debug.Log("!GO: " + (!GO));
     Debug.Log("GO == false: " + (GO == false));
     Debug.Log("GO != false: " + (GO != false));

This gives me:

 GO == null: False
 GO != null: True
 !GO: False
 GO == false: False
 GO != false: True
 Destroy
 GO == null: True
 GO != null: False
 !GO: True
 GO == false: True
 GO != false: False

Comment
Add comment · Show 11 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image spectre1989 · Aug 27, 2013 at 02:44 PM 0
Share

I'm checking every frame, here's the code I used:

 using UnityEngine;
 
 public class NewBehaviourScript : $$anonymous$$onoBehaviour 
 {
     private GameObject go;
     private Transform t;
 
     public void Start()
     {
         this.go = new GameObject( "go" );
         this.t = this.go.transform;
 
         Destroy( this.go );
     }
 
     public void Update()
     {
         Debug.Log( this.go == null );
         Debug.Log( (bool)this.go );
         Debug.Log( this.t == null );
         Debug.Log( (bool)this.t );
     }
 }
 
avatar image Bunny83 · Aug 27, 2013 at 02:59 PM 0
Share

Even with your test i get the desired output:

First frame:

 false
 true
 false
 true

because the object is still there

from second frame on:

 true
 false
 true
 false
avatar image spectre1989 · Aug 27, 2013 at 03:09 PM 0
Share

Oh yeah, you're right, I messed that up. This code on the other hand, does show the problem - it seems the reference has to have System.Object type:

 using UnityEngine;
 
 public class NewBehaviourScript : $$anonymous$$onoBehaviour 
 {
     private System.Object go;
     private System.Object t;
 
     public void Start()
     {
         GameObject temp = new GameObject( "go" );
         this.go = temp;
         this.t = temp.transform;
 
         Destroy( temp );
     }
 
     public void Update()
     {
         Debug.Log( this.go == null );
         Debug.Log( this.t == null );
     }
 }
avatar image Bunny83 · Aug 27, 2013 at 06:05 PM 0
Share

Well in Unity you usually don't work with System.Object references. System.Object uses it's own Equals function which of course "sees" the actual instance which is still there.

You can use this to check a reference if it's null or "fake null":

     public static bool IsNull(System.Object aObj)
     {
         return aObj == null || aObj.Equals(null);
     }

You can also make it an extension method if you like ;) This does work with "normal" classes as well as with UnityEngine.Object classes.

avatar image spectre1989 · Aug 27, 2013 at 10:09 PM 0
Share

Yeah I figured out that workaround, but if UnityEngine.Object was properly overridden then it wouldn't be a problem surely?

Show more comments

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

22 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Is there a way to Undo.RecordObject on a System.Object? 1 Answer

Do I have to check for null value before assigning a variable in Awake()? 1 Answer

Is there any way to successfully cast a UnityEngine.Object to a System.Object? 1 Answer

Is there a reason not to inherit from UnityEngine.Object if I wanted the basic functionalities that UE.Object gives? 1 Answer

Destroyed Object Stops Scipt 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges