Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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
7
Question by Tomer-Barkan · Nov 29, 2013 at 02:44 PM · gameobjectdestroymonobehaviourinterfacemissingreferenceexception

Destroyed object not comparing to null

I read that once a GameObject is destroyed, comparing it to null will return true. But I have this line of code which yields a MissingReferenceException saying the object has been destroyed but I'm still trying to access it:

 if (shootTarget != null) {
     // something
 } else {
     distance = shootTarget.GetDistance(this.transform.position);
 }

Any ideas why? Any other checks I can perform?

Update:

Ok I found the reason, but not a solution. shootTarget is not a MonoBehaviour per se, it's an interface I created, but the MonoBehaviour implements the interface and the actual value of shootTarget is a MonoBehaviour that's been destroyed, so comparing it to null doesn't yield true...

Any ideas how to work around this?

Comment
Add comment · Show 6
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 ArkaneX · Nov 29, 2013 at 02:53 PM 2
Share

Do you have == in your code, or is this some mistake in pasted text? It should be !=.

EDIT: if this is your actual code, then probably this is a reason of your error, though I would expect NullReferenceException in this case...

avatar image Tomer-Barkan ArkaneX · Nov 29, 2013 at 03:25 PM 0
Share

Yeah sorry, the code was in the else section and I forgot to change to != when I simplified it...

avatar image PhilRousse · Nov 29, 2013 at 03:20 PM 0
Share

@Arkanex You should post this as an answer. That look like a good answer. I would Up Vote that.

avatar image Tomer-Barkan · Nov 29, 2013 at 03:26 PM 0
Share

That would complicate things a bit too much, since I'm not destroying it from this script necessarily...

avatar image ArkaneX · Nov 29, 2013 at 03:29 PM 1
Share

@karljj - after tbkn comment, I think you should convert to answer :) +1

EDIT: I meant comment under my answer

avatar image yoyo · Sep 30, 2014 at 09:33 PM 0
Share

I edited the code snippet the fix the typo pointed out by @ArkaneX.

5 Replies

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

Answer by ArkaneX · Nov 29, 2013 at 03:52 PM

Inspired by @tbkn own answer, I did a bit of research. MonoBehaviour == operator is not overriden - it's Object == operator. But I see that Equals method is overriden as well, so you might try

 object.Equals(shootTarget, null)         // C#
 System.Object.Equals(shootTarget, null)  // JS

If code from your answer works, this should work as well.

EDIT: after a bunch of additional test it looks like the correct solution is the one posted by tbkn in a comment below:

 shootTarget == null || shootTarget.Equals(null)

The first condition prevents situation when the shootTarget really becomes null, while second one correctly uses Equals overriden in UnityEngine.Object.

Comment
Add comment · Show 4 · 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 Tomer-Barkan · Nov 29, 2013 at 04:17 PM 1
Share

It doesn't... but something very similar does:

if (shootTarget == null || shootTarget.Equals(null))

Not sure why if they overload Object.Equals...

avatar image Tomer-Barkan · Nov 29, 2013 at 04:20 PM 0
Share

This is the best solution because it doesn't require to force cast... But please change your answer based on my previous comment so it's accurate.

Thanks for the help!

avatar image ArkaneX · Nov 29, 2013 at 09:50 PM 0
Share

Very good catch - answer updated.

avatar image Nition · Jan 01, 2015 at 09:10 PM 0
Share

Thanks for this answer. I had the same issue as the OP (referencing a $$anonymous$$onoBehaviour as an interface) and indeed == null returns false but .Equals(null) returns true.

avatar image
2

Answer by Tomer-Barkan · Nov 29, 2013 at 03:37 PM

Ok, figured out a possible solution, though not the most elegant. Will keep this question open a bit more to see if anyone knows a more elegant solution.

Apparently a MonoBehaviour's operator == is overridden to return true when comparing a destroyed object to null. Apparently, in C#, when you override an operator of a class, it will not match the overridden operator when you compare an instance of that class that is assigned to an interface variable. This is to do with the fact that operator resolution is done in compile time, and not runtime like virtual methods.

 MonoBehaviour myMono;
 MonoBehaviourInterface myMonoInterface = myMono;

 // this will use the overloaded operator== of MonoBehaviour
 if (myMono == null) {}

 // this will NOT use the overloaded operator== of MonoBehaviour
 if (myMonoInterface == null) {}

Thread in which this is discussed: http://stackoverflow.com/questions/728434/operator-overloading-with-interface-based-programming-in-c-sharp

So my solution would be to cast shootTarget to MonoBehaviour when doing the comparison to null. Although I don't know the exact class of shootTarget, I do know it is a subclass of MonoBehaviour, so this works.

 if (((MonoBehaviour)shootTarget) == null) {
     // something
 } else {
     distance = shootTarget.GetDistance(this.transform.position);
 }
Comment
Add comment · Show 2 · 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 PhilRousse · Nov 29, 2013 at 03:40 PM -1
Share

O$$anonymous$$G, that a really specific problem. You should probably rename the question to reflect the implication of the interface.

avatar image Tomer-Barkan · Nov 29, 2013 at 03:43 PM 2
Share

I didn't know that when I asked the question. I expect others that encounter this problem not to know that either and use the same terms that I used, so better not to change the name...

avatar image
2

Answer by yoyo · Sep 30, 2014 at 09:38 PM

Since the interface doesn't know about the original MonoBehaviour's operators, you won't get the over-ridden behaviour of operator == (from UnityEngine.Object), which is where destroyed objects are "equal" to null.

The following test will work for interface implementations that may or may not be MonoBehaviours.

 if ((shootTarget == null) || ((shootTarget as UnityEngine.Object) == null)) {
     // something
 } else {
     // something else
 }

The first check handles the general case of the object actually being null. The second check handles the case of a destroyed Unity object.

Comment
Add comment · Show 1 · 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 Glurth · Mar 16, 2016 at 08:12 PM 0
Share

+ 1 for: "which is where destroyed objects are "equal" to null."

avatar image
1

Answer by karljj1 · Nov 29, 2013 at 03:22 PM

I have had this issue in the past. Calling destroy on a monobehaviour will not destroy it instantly however it will mark it as destroyed. When you destroy the object also set it to null to be extra safe.

E.G

Destroy( shootTarget ); shootTarget = null;

Edit:

I assume that shootTarget is some property of an other script in which case you are fine to set it to null from an external script. Its still the same variable.

Comment
Add comment · Show 4 · 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 PhilRousse · Nov 29, 2013 at 03:33 PM 1
Share

By setting shootTarget = null, you're just setting it's reference to null, not the gameobject. And if you call Destroy on that gameObject, I think it's a good thing to not try to do anything with it after. So I think it's a good thing to do.

avatar image ArkaneX · Nov 29, 2013 at 03:34 PM 2
Share

Assu$$anonymous$$g karljj method will help, then why not add this additional line in any script you call Destroy? If you use C# (or Boo) you can even write an extension method DestroyAndSetToNull and use it ins$$anonymous$$d.

avatar image Tomer-Barkan · Nov 29, 2013 at 03:40 PM 1
Share

Think of it this way:

5 objects, Obj1 - Obj5, all have reference to Obj6, they are all shooting at it. At some point, say Obj1 shoots Obj6 and it is killed, so Obj1 calls Destroy() of Obj6. Say I null the reference of Obj1 so that it no longer references Obj6. But Obj2 - Obj5 are still referencing it, because they are not the ones that destroyed it. So I have to iterate all objects, check whether they are referencing Obj6, and set to null... This is too much of a hassle, and is exactly why Unity came up with comparing an object to null will return true when it has been destroyed, that way you don't have to clear all the references.

avatar image ArkaneX · Nov 29, 2013 at 04:04 PM 1
Share

Right - in the case you described this is not appropriate.

avatar image
1

Answer by amirebrahimi · Nov 24, 2016 at 04:28 AM

The fixes above didn't work for me, but it's possible that some of these stopped working during the 5.x era. Here's a workaround that I found:

Equals(obj, "null")

Comment
Add comment · 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

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

using Contains(gameObject) to find and destroy a gameObject from a list 2 Answers

Why does my bullet prefab get destroyed? 1 Answer

Why is my MonoBehaviour never being deleted? 0 Answers

Destroy a Gameobject with a UI Button 3 Answers

Deleting GameObjects 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