EDIT: This explains everything! - Unity creates managed fake wrappers around your UnityEngine.Objects when you destroy them. That means if you destroy a UEObject, the C# wrapper could still be not null. The == is implemented in a custom way so that when you destroy a UEObject checking == null will return true. This obviously doesn't play well with generics.
This is literally driving me insane. I have this method right here:
public static void AssertNotNullAfterAssignment<T>(ref T value, Func<T> get, string msg) where T : class
{
if (value == null)
value = get();
if (value == null)
throw new NullReferenceException(msg);
}
I'm calling it on a reference that is null at the start:
AssertNotNullAfterAssignment(ref fovMeshFilter, GetComponent<MeshFilter>, "fovMeshFilter");
What's really insane, is that the check if (value == null)
is returning false! even though the value IS null!
Here's a short video I made showing this.
What's interesting though, if I copy/paste the method code to the method I used it in (in OnEnable) it works (pretty much what I have commented in OnEnable in the video)
So... it works if it was outside the assertion method, but not inside. I also tried Equals
instead of ==
but the same.
Anybody has any idea what's going on?
Edit: Here's OnEnable, the method I'm calling the assertion from:
private void OnEnable()
{
//if (fovMeshFilter== null)
// fovMeshFilter= GetComponent<MeshFilter>();
//if (fovMeshFilter== null)
// throw new NullReferenceException("fovMeshFilter");
AssertNotNullAfterAssignment(ref fovMeshFilter, GetComponent<MeshFilter>, "fovMeshFilter");
}
If I use the uncommented lines it works as expected, but the assertion method doesn't work for some only-god-knows-why reason.
Edit1: What we have here?
Edit2:
Edit3:
So after the great help from this awesome community, and couple of tests I came to the solution. I could have sworn it was one of the very first things I tried! you must believe me! XD - It was just to use .Equals
instead of ==
- Like @Edin shows in his answer, doing a ==
on a generic object seem to call System.Object
's ==
- But, calling .Equals
should always resolve to the correct overload of Equals
. I don't know why is it this way, I mean, why don't the '==' also resolve to the correct overload?
Your object is not null. Seeing null
in debugger does not mean it is a null reference. If you can expand object in the debugger, it is most certainly not null reference. It might be that the DebuggerDisplay
string or ToString()
method return "null"
in your case but that is not the same as null reference.
Take an example of this class
[DebuggerDisplay("null")]
class A { }
An instance a
of A
var a = new A();
will be displayed as a|null
in the debugger when you run over it with your mouse.
Your T
most certainly has this attribute. ToString()
override which returns "null"
would add additional curly braces around the string: a|{null}
.
EDIT:
Seeing your Edit2, made me realize what your real problem might be. Your ==
operator is most probably overriden, so that it returns true in some cases when you compare an instance of your class to null, although an instance itself is not null. However, in generic method it is not known what type your parameter is at compile time, therefore the most general operator will be applied on your T
parameters, which is reference comparison. This is well described in the following thread: C# generics class operators not working
That could be the reason why the comparioson in OnEnable()
works, and the comparison inside your generic method does not.
However this is not completely proven, since I cannot see your code. But you could verify that.
And here is a full working example of the operators not working properly in combination with generics:
class Person
{
public string Name { get; set; }
public static bool operator ==(Person left, Person right)
{
// we consider Person null when it either has no Name or it is a null reference.
if (object.ReferenceEquals(null, left) || left.Name == null)
return object.ReferenceEquals(null, right);
return left.Equals(right);
}
public static bool operator !=(Person left, Person right) { return !(left == right); }
// Note that == and != operators should ideally be implemented in combination of Equals() override.
// This is only for making an example for this question
}
private static bool IsNull<T>(T val)
{
return val == null;
}
static void Main(string[] args)
{
Person person = new Person();
//this will display: person == null => True
Console.WriteLine("person == null => {0}", person == null);
//this will display: IsNull<Person>(person)=> False
Console.WriteLine("IsNull<Person>(person)=> {0}", IsNull(person));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With