Testing for a Destroyed object... that's an interface.

So I have an interface, IHasContextMenu. I attach that to some scripts that attach to gameobjects, and that provides methods that allow right-click popup menus when those objects are right-clicked.

Recently, I made some changes to some prefabs where those scripts are added to some gameobjects dynamically. Gameobject is instantiated from a prefab, placed in an object pool, and when it’s needed, it’s given out. The correct ItemTypeScript is applied (which has the IHasContextMenu interface) and all is well.

Problem: When that object is released, and the ItemTypeScript is destroyed, the script that handles the context menu, which caches the IHasContextMenu reference to the script stops working right.

Did some research. Unity objects which are Destroyed will still return false if tested for == null. Ok, got it. Website I found said that instead of testing == null, just using the object itself returns a bool, so you can test something like:


Destroy(scriptRef);
if(scriptRef == null) {
// This will NOT run, if the scriptRef has been Destroyed. testing == null will eval false because weird Unity stuff
}
if(!scriptRef) {
// THIS will correctly evaluate, as Unity gameobjects have overloads for this
}

The problem I’m facing is I’m not using a reference to a SCRIPT. I’m using a reference to an INTERFACE. The interface resides on quite a few different scripts, so caching the reference to IHasContextMenu and just calling contextMenuRef.menuItems works great.

Except that once that reference is Destroy’ed, testing == null results in false. And apparently, I can NOT do a boolean if(!contextMenuRef) because that’s not a built in overload.

So if a cached reference to an interface is Destroyed, I can’t find a way to test for that. Yes, I COULD make sure the destroying script also sets the reference to null, but that is a LOT of extra code in a lot of places.

Is there a decent solution for this? The best I could think of was checking if GetComponent() returned anything, but that seems excessive.

If you really want to rely on Unity’s destroyed object magic, you could probably do something like this:

if (!(scriptRef as UnityEngine.Object)) {
  // If we got here, the object was destroyed (or never assigned, or it's not a UnityEngine.Object).
}
4 Likes

This is a pickle to be sure. The null check is effectively useless.

One thing I’ve done is when I implement the interface, check if .gameObject has been destroyed or not, and don’t do the rest of the function. That doesn’t get you through all cases (such as needing to return a valid thing), but it’s something.

An alternate plan is to loosen the coupling, such that the interface functions only transact against local variables (such as a mailbox or queue) and then Update() is charged with doing something with the posted data. Again, doesn’t handle all cases, such as “give me your X” case.

If you must, you could always implement a second interface, IExistable and have all calling sites responsible for getting that and testing it. Alternately you could implement a bool DoYouStillExist() method into ALL your interfaces.

In all cases, meh, not great. But interfaces are still greatly worthwhile, imnsho.

What I did for now, due to the lack of a good/elegant solution, is check for the GetComponent still exists on the gameObject in question. These checks don’t happen that often, so it’s not like it will cause any performance issues. It just feels sloppy and I like my code to be a bit cleaner than that.

I’ve worked a little with operator overloads - I had a lot of fun implementing a custom == overload for my ItemData so I could test a few different things. Totally not necessary, a method would have handled it just fine, but, was a cool learning experience.

That being said, how would you overload something to be testable as bool with a simple if check, since technically it’s not using any operator.

If that question isn’t clear, it’s based off of my origial question above.


scriptInstance = AddComponent<SomeScript>();

Destroy(scriptInstance);

if(scriptInstance) {
// I'm still here!
} else {
// Nope, I was destroyed
}

That if check… personally I love those checks. I come from a long background in C and it took me a long while to get used to all the == null and != null checks, when I used to just do if(!thing).

How would you go about overloading that?

Actually it is using an operator!

You would create an implicit conversion-to-bool operator. Here’s some documentation from Microsoft on how to write conversion operators in C#: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators

Their example in that link is for conversion between Digit and byte, but you can write your own between any two types you want.

1 Like

Thanks for the link. One of the hardest parts (for me anyway) of learning new coding techniques/languages is not knowing the terminology to even google for. I’ll give that a read. Thanks again.

Unity actually implements an implicit type conversion operator from UnityEngine.Object to bool. That’s why you can simply use a reference of type UnityEngine.Object in place where a boolean is expected (like in an if statement). Note that type conversion operators can only be implemented in one of the two types you want to convert between. So this is not really an option for interfaces since you can not declare operators inside interfaces. Since we want a conversion to bool that’s also not an option. The best solution for interfaces would be an extension method. Extension methods have to be declared inside a static class. So you can use a method like this:

public static class UnityObjectAliveExtension
{
    public static bool IsAlive(this object aObj)
    {
        var o = aObj as UnityEngine.Object;
        return o != null
    }
}

This would essentially give every type an IsAlive method which would always return false except it it’s a UnityEngine.Object derived type and it’s still alive. Note that I would not recommend attaching an extension method to the System.Object type as this method would be valid on literally any type. Though it would be useless on all types except UnityEngine.Object derived types. For example this would be possible as well:

int v = 5;
if (v.IsAlive())
    // will always be false since the as-cast inside the method will fail and evaluate to null

So I would recommend to create a seperate interface like IHasAliveCheck and restrict the extension method to this interface:

public interface IHasAliveCheck { }
public static class UnityObjectAliveExtension
{
    public static bool IsAlive(this IHasAliveCheck aObj)
    {
        if (aObj is UnityEngine.Object o)
            return o != null;
        return aObj != null;
    }
}

Now your own interface can simply implement this IHasAliveCheck interface and it gets the extention method:

public interface IHasContextMenu : IHasAliveCheck
{
    // [ ... ]
}

That’s still kinda hacky but it provides a universal null check that does handle UnityEngine.Object objects correctly. So only when the passed object is of type UnityEngine.Object we use Unity’s custom null check. In all other cases we just use the ordinary null check. This IsAlive method will always return true except when the passed reference is either null or a fake null UnityEngine.Object.

Note that extension methods are just syntactic sugar in the compiler. It’s essentially a fallback solution. However that means if your actual interface has its own IsAlive method, the extension method would not work / would not be visible. They only kick in when the compiler can’t find a method with this name / signature.

Fun fact

Technically instance methods of objects work just like extension methods. The actual code for all methods is always static. Instance methods just have an implicit “first” argument which is the instance reference they should be executed on. All this is just hidded behind syntactic sugar of the compiler. The only methods that work a bit differently are virtual / abstract method or interface methods as they require dynamic dispatch. Though after the resolving of the actual method it again works the same way. This can be seen when looking at the CreateDelegate method of the reflection system. For instance methods you have to provide the “firstArgument” which essentially provides the “this” reference inside the method itself. See this blog on dynamic dispatch in C#.

The programming language Lua actually has a neat feature that provides some sort of “instance” methods for tables. Lua has the .(dot) operator to access a value inside a table by name. Since functions in lua can simply be stored in a table value you can call methods like this

someTable.myFunc()

In addition to the “dot” operator lua provides the “colon” operator :. This is also just syntactic sugar. It simply passes the table as the first argument. So when doing

someTable:myFunc(5, 3)

you actually do

someTable.myFunc(someTable, 5, 3)

3 Likes

I don’t know if its the best solution but for me worked smth like this:

if(scriptRef == null)
if((Object)scriptRef == null)

This only works if you can guarantee that the object behind the interface is an UnityEngine.Object derived class. You would get an invalid cast exception in any other case. You could use an “as” cast instead. Though this would just silently filter out any valid instances which are not derived from MonoBehaviour or ScriptableObject. Depending on your usecase it may not matter. Though it does not apply to all cases.

i just use something like this:

if (interface == null || interface.Equals(null))
{
//doesnt exist
}
else
{
//exists
}

no idea why this works, but it does

3 Likes

Yes, this is a way because operators like “==” are not virtual and can not be overridded while the Equals method is a virtual method and the UnityEngine.Object class has overridded it properly.

The issue is that the compiler chooses which operator it should use based on the variable type, not on the actual type which is unknown at compile time. Virtual methods are resolved at runtime as classes which have virtual methods have a v-table (virtual function pointer table) and when you call a virtual method, the call actually looks up which actual method should be used. Though as I said, operators are not virtual methods. So when you store a UnityEngine.Object type in an interface type variable (or System.Object type variable), the custom == operator that Unity provides is not used but the default one.

Your solution has two steps:

  • The normal == operator is used which can only detect true null values. So when the null check tells you that there actually is an instance, that instance may be “dead” / “fake null”.
  • You can only call the Equals method on an actual instance, so the first null check is necessary. The virtual Equals method of UnityEngine.Object types will return true when you compare against “null” if the object is dead. So it fakes that it is null.
3 Likes

The thing is, when you cast a Unity object to an interface (either directly or by using GetComponent) C# won’t use any operator override/implicit/explicit converters from the Unity object, which bypasses the Unity objects “fake” null check (i.e. Unity considers an object as null if it has been destroyed, even if the C# object is still alive).

What I use in my interfaces to solve this is just to add an “IsAlive” bool to my interfaces. Then in Unity objects I implement it as:

public interface IHasContextMenu
{
    bool IsAlive { get; }
    // Other IHasContextMenu properties/methods...
}

public class MyClass : MonoBehaviour, IHasContextMenu
{
    public bool IsAlive => gameObject != null;
    // Other IHasContextMenu properties/methods...
}

If you have a lot of interfaces that need to have an IsAlive check, just create a base interface (for eg. IGameEntity) that has the bool IsAlive (and any other useful shared properties like Transform…etc) and make other interfaces inherit from it.

You could also go the extension method way like @Bunny83 suggested. But personally I like to be explicit in my code, so I prefer a bool in the interface itself.

1 Like

Right. Hopefully in the future we get something like that natively. They were thinking about deprecating the == operator overload but I think they considered it a too big of a change as it would even break a lot if internal code. So they would need to introduce a new system in parallel, switch all internal stuff and much later may get rid of the operator.

Though many were begging to get rid of the operator but they don’t quite get the implications. All the fancy null operators would still not work. So things like ??, is not null or ?. still wouldn’t do what is intended.

Extention methods have the advantage that they also work with true null references. Your IsAlive bool check always needs to be paired with a null check. While technically this is always necessary, an extension method can do both things at once. Though requiring both check maybe would force the users to learn and understand the reason behind it and why it’s actually necessary :slight_smile:

1 Like

I haven’t realized this before now, but the fact that UnityEngine.Object.Equals(null) can’t handle actual null references, only destroyed objects, can be a good thing as well.

For example, consider this code:

class OnDisableExecuteCommand : MonoBehaviour
{
    ICommand command;

    void Awake() => command = GetComponent<ICommand>();

    OnDisable()
    {
        if(!command.Equals(null))
        {
            command.Execute();
        }
    }
}

Here I would see it as very beneficial that the null check can’t accidentally hide erroneous situations where no ICommand component was ever attached to the game object in the first place.

But the way I usually handle null-checking interface type variables is like this:

void OnDisable()
{
    if(command != Null)
    {
        command.Execute();
    }
}

Where the Null object’s class has an overloaded == operator, which can handle destroyed objects as well:

public static bool operator ==(object @object, Null @null)
    => @object is Object unityObject ? unityObject == null : @object is null;

It always bothers me a little bit when the argument with the this modifier in an extension method is null-checked; I worry that it’s not very intuitive to somebody using the extension method, that it can in fact handle null references.

1 Like

Yes that’s why nullable references is such a great feature in recent C# versions, as it convey if the method accepts a null object or not. There’s also [CanBeNull]/[NotNull] attributes if you’re using Rider or VS with Resharper with older C# versions that do not support nullable references.

1 Like

@Nad_B Good point! I haven’t enabled nullable reference types in any of my projects yet, but I’m planning to do so in the next one I start. They’ll probably make it much more difficult to do accidental error hiding in situations like this.

I’ve switched over from JetBrain’s CanBeNull/NotNull to Microsoft’s variants AllowNull/DisallowNull/MaybeNull/NotNull - and the rest of them. These ones are supported on VS without ReSharper as well.

I like being very explicit about which parameter and return values are allowed to be null, and getting static analysis to help ensure that these contracts are followed is totally awesome :sunglasses:

1 Like

I do it like this.

public static class Ex
{
    public static T IsNull<T>(this T o) where T : UnityEngine.Object => o ? o : null;

    public static T IsAlive<T>(this T o) where T : class
    {
        if (o is UnityEngine.Object uo)
            return uo.IsNull() as T;
        else
            return o;
    }
}

example

someInstance.IsAlive()?.DoSomething();

That’s bad name design because everyone would expect that methods that start with “Is” would return a boolean value. You essentially just create a wrapper that ensures that fake null objects actually evaluate to null. Both of your methods IsNull and IsAlive do essentially the same thing, even though they have pretty much opposite names. A method IsNull should return true when something is null and false if it isn’t. IsAlive would do the opposite.

So highly misleading method names. It’s difficult to choose a proper descriptive name. But something like “ToTrueNull” or “AsTrueNull” or something like that would make more sense in your case.

        public static T AsTrueNull<T>(this T o) where T : class
        {
            if (o is UnityEngine.Object uo && uo == null)
                return null;
            return o;
        }
4 Likes

I have a method very similar and I name it “SanitizeRef”… I view it as cleaning off the unity “== null” residue nonsense.

2 Likes