简体   繁体   中英

Missing Reference Exception with Rigidbody Field and ?? operator

I keep getting this exception: "MissingReferenceException: The object of type 'Rigidbody' has been destroyed but you are still trying to access it."

The problem with it is that i only accsess it by this field:

    private Rigidbody m_Rigidbody = null;
    private Rigidbody Rigidbody => m_Rigidbody ?? (m_Rigidbody = GetComponent<Rigidbody>());

and my exception is thrown at this line:

    public float CurrentSpeed => (Rigidbody?.velocity.magnitude ?? 0f) * ((m_SpeedType == SpeedType.MPH)?2.23693629f : 3.6f);

What my question is, how is it possible that i get a null reference, even if the object has a rigidbody (every object that throws this exception still has its rigidbody active and attached if the error occures).

Thanks in advance and have a nice day.

You shouldn't use ? or ?? on anything inheriting from UnityEngine.Object AT ALL.

It is somehow related to how Unity implemented their == and != operators internally for UnityEngine.Object (which is basically the super class for any Component, GameObject, Asset etc)

See also Possible unintended bypass of lifetime check of underlying Unity engine object where the makers of the Re-Sharper Plug-In for Unity explained it further based on UnityBlog - "Custom == operator, should we keep it?"

Checking for ==null and thereby also and in particular using the ? and ?? operators is simply bypassed by UnityObject .

Why?

On the surface: After calling Destroy (or eg if it is a serialized field and not referenced yet) an Object in Unity does not exist anymore. BUT it is not really ==null , it rather still holds some meta data and is only - how they state it

a fake null object .

That's actually the reason why you do not get a NullReferenceException but the Unity built-in MissingReferenceException giving you a hint why you usually would get a NullReferenceException at this point. It could eg state

The object of type 'XY' was destroyed but you are still trying to access it


However in particular for this reason UnityEngine.Object has an implicit bool operator returning

Does the object exist?

so eg if(destroyedObject) after detroyedObject has been called Destroy(destroyedObject); or it is is a field that was never assigned yet will now not be executed (anymore) since it is now false .


So what you want to do especially for stuff being Destroy ed would be actually using that operator like

private Rigidbody m_Rigidbody = null;
private Rigidbody Rigidbody
{
    get
    {
        if(m_Rigidbody) return m_Rigidbody;

        m_Rigidbody = GetComponent<Rigidbody>();

        return m_Rigidbody;
    }
}

For readability reasons I'm not a fan of making things like this an expression body anyway.

Your other property would then accordingly also be

public float CurrentSpeed => Rigidbody ? Rigidbody.velocity.magnitude * ((m_SpeedType == SpeedType.MPH) ? 2.23693629f : 3.6f) : 0f;

In general any my opinion: Whenever there might be more work hidden inside a property then only simplifying references (like here eg GetComponent ) it should rather be a method. But maybe this is just a matter of taste.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM