1

https://i.stack.imgur.com/jyYpi.gif So I've been doing Unity C# programming for about 6 years now, and I only JUST found out about C# null v.s. Unity "null" (that's what you get when Unity is how you learn C# I guess). Needless to say, quite a spanner in the works, as I've been using the ?. operator tons in projects over the years which simply won't work with Unity "null" due to the fact that Unity is written in C++ and C# is just the layer in which projects are written, Unity "null" AFAIK really meaning the UnityEngine.Object is destroyed but the reference is still there for debugging purposes only becoming C# null once GC'd whenever that is.

I've done some looking into the differences between Unity "null" and C# null, and I'm pretty confused on why I'm still having null-checking problems. You can see in the above GIF that inst is clearly Unity "null" and not C# null. I do a comparison that reads inst==null which from what I have been told should be true in this context since Unity overrides the == operator for all UnityEngine.Object instances and accounts for this as opposed to not considering things like ?.. However, as you can also see in the GIF, the bool that stores the result of this == comparison (for debugging purposes) is false, which is what confuses me, I'm explicitly using the == operator I'm told UnityEngine.Object overrides for exactly this situation yet I'm getting the same results as if I weren't to be comparing explicitly.

Do note a few things about the provided GIF:

  1. Some of the function in the GIF is needlessly verbose to help me debug this issue
  2. TRefType is contracted by where to be a class, so it can be an object or a UnityEngine.Object and I need a way to null-check for either.

What's going on?! This whole C# null v.s. Unity "null" thing alone has messed up my flow, and now my understanding of the issue might not be completely there either! For more info on the whole topic, assuming you're as lost as I was when I found out about Unity "null", check this out: https://blog.unity.com/technology/custom-operator-should-we-keep-it

Here are some other StackOverflow threads I checked out before making this post that only further convince me that my current understanding is correct and yet I'm still not getting the results I expect: Why does C# null-conditional operator not work with Unity serializable variables? Unity : this == null returns true. How can this happen?

Here is the function I'm working with in isolation of the rest of my project as a code block for your convenience in replying. You can just ignore the other case outcomes, they are acting as-intended right now:

        private bool IsNull(TRefType inst)
        {
            Type instType = null;

            if(inst!=null)
                instType = inst.GetType();

            switch (instType)
            {
                case Type t when t == typeof(string):
                    return string.IsNullOrWhiteSpace(inst.ToString());
                case Type t when t == typeof(IEnumerable):
                    if (t != typeof(IDictionary))
                        return CollectionHelpers.AnyAllScanners.AnyElementsNotNull(inst as IEnumerable);
                    else
                        return CollectionHelpers.AnyAllScanners.AnyElementsNotNull(inst as IDictionary);
                default:
                    bool iN = inst==null;
                    bool iTN = instType == null;
                    return iN || iTN;
            }
        }

Any help greatly appreciated!

1 Answers1

1

It seems that IsNull is part of some generic class and for all reference types used as generic type parameter the generic method implementation will be shared (i.e. compiler will produce one method for all reference types passed as generic type parameter to prevent the code bloat) so the operator resolution happens at compile time, hence in this case this is "C#'s null".

You add check for UnityEngine.Object:

switch (instType)
{
    // ...
    case _ when typeof(UnityEngine.Object).IsAssignableFrom(instType):
        return (inst as UnityEngine.Object) == null; 
    // ...
}
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • TYSM for getting back to me! I started to feel about the same the last few minutes, and this answer seemed promising and cleared up the trivialities a bit for me, but now I have the issue that because `TRefType` is `where` contracted to a `class`, there is no cast from `TRefType` to `UnityEngine.Object`. Is there something else I could contract `TRefType` to be in order to only be reference types? https://files.catbox.moe/w4av1b.png – Spring E. Thing Jul 21 '23 at 23:49
  • @SpringE.Thing have not worked with Unity for a long time and do not have setup at the moment, try `((UnityEngine.Object)(object)inst)` or `(inst as UnityEngine.Object)` – Guru Stron Jul 21 '23 at 23:52
  • I tried the second option, and that was compilable even with the `where` restriction, which gave me a good feeling since the logic of your answer to me is sound, yet sadly even so it doesn't recognise that `inst` is a `UnityEngine.Object` or at least descends from it as `inst` is a `UnityEngine.GameObject`, this I really don't understand, I was expecting it to at least pick the right `case`. https://files.catbox.moe/rixz3s.png – Spring E. Thing Jul 21 '23 at 23:57
  • @SpringE.Thing yep, stupid mistake by me, `when t == ...` -> `typeof(UnityEngine.Object).IsAssignableFrom(t)` – Guru Stron Jul 22 '23 at 00:01
  • 1
    That did the trick, thank you SO much! You have no idea how many work nights I've wasted on this one concept, and I'm even more thankful the answer you gave is so clear and understandable. It wasn't me misunderstanding the `==` `override` after all, it was just that the generic nature of the `class` assumed the wrong `==` `override` to use and I needed to make it explicitly clear the types being dealt with. – Spring E. Thing Jul 22 '23 at 00:04
  • @SpringE.Thing was glad to help! If answer works for you feel free to upvote it and mark as accepted one (checkmark to the left) ;) – Guru Stron Jul 22 '23 at 00:06
  • 1
    Done! TY Again! : ) – Spring E. Thing Jul 22 '23 at 00:21