I am getting a ReSharper (2018.1) warning for Possible 'System.NullReferenceException' when I check for null implicitly with if (obj) instead of if (obj ! = null).
For example:
using JetBrains.Annotations;
using UnityEngine.UI;
public class CanBeNullTest : MonoBehaviour
{
[CanBeNull] public Button Button { get; set; }
private void EnableButton_explicitCheck()
{
if (Button != null) Button.enabled = true;
}
private void EnableButton_implicitCheck()
{
if (Button) Button.enabled = true;
}
//private void EnableButton_cSharp6()
//{
// // null propagating operator is not available in C# 4
// Button?.enabled = true;
//}
}
Only the implicit null check shows the ReSharper warning:
I looked at the ReSharper page for "Why is ReSharper suggesting this" and the links there, but I couldn't find an explanation for this.
Is this a ReSharper limitation? Or is it incorrect or bad style to check for null implicitly?
Although it doesn't actually produce a NullReferenceException, because your Button can be null and the if statement triggers an implicit conversion to boolean that produces the NullReferenceException, it is still valid warning in general.
Something similar in Java,
Check if null Boolean is true results in exception
If you don't like extra null checks, you may be able to do the C# equivalent of the following Java code,
if (Boolean.TRUE.equals(value)) {...}
The if (Button) involves an implicit conversion to bool, which doesn't produce a NullReferenceException in this case, but it is a valid warning in general.
Related
I'm confused about the return value of GetComponent if the requested component is not attached to the object. According to the Unity documentation, GetComponent should return null. However, what appears to be happening is that GetComponent is returning a "null" object of the requested type, rather than the value null.
In this example, my game object does not have a CircleCollider2D attached to it. When I set a breakpoint on the line CircleCollider2D x = GetComponent<CircleCollider2D>();, I get this result
Why is the returned value not null?
EDIT:
Here's a full screenshot of the code and the values in the debugger.
ANOTHER EDIT:
Could it be that Unity has overloaded the == operator so that GetComponent always returns a object, but the object can have an internal "null" state which returns true when compared to null? I can see the following declarations in the UnityEngine namespace
public static bool operator ==(Object x, Object y);
public static bool operator !=(Object x, Object y);
It seems like GetComponent<T>() doesnt return TRUE null. Instead it returns new T with default values that fires MissingComponentException when using any null field. GetInstanceID() and GetHashCode() work because they only use int m_InstanceID which is set to default 0. Not sure how ToString() works but it probably returns "null" when m_InstanceID == 0.
Proof:
void Start()
{
CircleCollider2D getComponent = GetComponent<CircleCollider2D>();
CircleCollider2D empty = null;
CircleCollider2D newCC = new CircleCollider2D();
Debug.LogFormat("getComponent.GetInstanceID() {0}", getComponent.GetInstanceID());
Debug.LogFormat("newCC.GetInstanceID() {0}", newCC.GetInstanceID());
try
{
Debug.LogFormat("empty.GetInstanceID() {0}", empty.GetInstanceID());
}
catch (System.NullReferenceException e)
{
Debug.Log("empty.GetInstanceID() doesnt work, im true null");
}
try
{
string t = getComponent.name;
}
catch (System.Exception e)
{
Debug.Log(string.Format("getComponent fires {0} when any field is null",
e.ToString()));
}
try
{
string t = newCC.name;
}
catch (System.Exception e)
{
Debug.Log(string.Format("newCC fires {0} when any field is null",
e.ToString()));
}
}
Results:
getComponent.GetInstanceID() 0
newCC.GetInstanceID() 0
empty.GetInstanceID() doesnt work, im true null
getComponent fires UnityEngine.MissingComponentException
newCC fires System.NullReferenceException
Also:
getComponent.GetHashCode() = 0
getComponent.ToString() = "null"
Why getComponent == null is true? Usually it's just:
`getComponent.GetInstanceID() == otherComponent.GetInstanceID()`
In o == null case it's:
return !(
o.GetCachedPtr() != IntPtr.Zero || (!(o is MonoBehaviour) &&
!(o is ScriptableObject) &&
Object.DoesObjectWithInstanceIDExist(o.GetInstanceID())));
So i guess object with InstanceID = 0 never exists.
Search for decompiled UnityEngine/UnityEngine/Object.cs if u want to know more.
Could it be that Unity has overloaded the == operator
Tldr: Yes.
Why is the returned value not null?
According Custom == operator, should we keep it? :
When a MonoBehaviour has fields, in the editor only, we do not set
those fields to “real null”, but to a “fake null” object.
Why? According that article, basically for two reasons:
On Editor mode: get more contextual information on invocations, so if you have an exception you will be able to know which object was the cause.
Every that comes from UnityEngine.Object are wrapped in a C# object to keep the reference to the Unity C/C++ GameEngine Object. In the editor/code we work with the C# elements but those are just a reference to the 'real' c++ objects. Now, the lifetime of those 'real' c++ objects are handled explicitly (if you destroy something the C++ object it will be destroyed and the allocated memory it will be freed) but the C# object will be completely destroyed when the Garbage Collector decides to free that memory. So you will have a not null C# object pointing to a null C++ object. With this fake null trick you will know that this specific C# object is null because in the C++ side it was destroyed.
This is also important when if you have a singleton and if (sm_Instance == null) is not working as expected, you can use: if (EqualityComparer<T>.Default.Equals(sm_Instance, null)) instad.
Edit: Probably this can be caused if your singleton use generics and your type constrain is class
public class Singleton<T> where T : class {
This will cause to use the == operator of a class object, even when your Singleton is a GameEngine Object. One fix for that? Instead of class you can use UnityEngine.Object, like:
public class Singleton<T> where T : UnityEngine.Object {
Related Thread:
https://forum.unity3d.com/threads/null-check-inconsistency-c.220649/#post-1775701
Ps: If you go to UnityEngine.Object assembly, you will be able to see the overload:
Almost at the end...
if you are still looking for solution this worked for me`
var component = parent.GetChild(i).GetComponent<T>();
if(component != null)
{
if (component.ToString().Equals("null") == false)
{
list.Add(component);
}
}
GetComponent is expected to return object of type 'Component. Hence it is not expected to return "null" rather ~null is expected value. Perhaps this strange behavior should be reported to unity3d,
For example, I have a login form and the another form. Some button is disable, because some button is for manager only and I try this code, then I debug it after debugging this message pop-up Object reference not set to an instance of an object.
if (labelLogAs.Text == "Manager")
{
(this.Owner as MainMenu).buttonInventory.Enabled = true;
}
You get this error, because the operation with as operator returned null. To avoid this error you need to perform a security check.
You have two options to perform this security check:
Using as operator:
if (labelLogAs.Text == "Manager")
{
var owner = this.Owner as MainMenu;
if(owner !=null)
owner.buttonInventory.Enabled = true;
}
Using is operator:
if (labelLogAs.Text == "Manager")
{
if(this.Owner is MainMenu)
((MainMenu)this.Owner).buttonInventory.Enabled = true;
}
It is his discretion which security check use to avoid this error.
If you get the error "Object reference not set to an instance of an object", it means that something is null. Please debug it to find what exactly is null. In your case, one of the following expressions is null and you can find it by stepping over the code in the debugger and watching the expressions:
labelLogAs
this.Owner as MainMenu
(this.Owner as MainMenu).buttonInventory
an addition to Ilya Kogan answer. You should do null checks when using the as operator like so:
var owner = (this.Owner as MainMenu);
if(owner == null)
return;
This is just an example and doesn't necessarily fit your needs.
I have the following code which gives a warning "possible unintended reference comparison; to get a value comparison, cast the right hand side to type string":
// oControl is of type Control
if ((ocontrol.Name == oDataRowView["ConName"].ToString()))
{
//Do stuff
}
else
{
//Do other Stuff
}
I've tried to fix it using each of the following but I still get a warning
if ((ocontrol.Name == Convert.ToString(oDataRowView["ConName"])))
{
//Do stuff
}
else
{
//Do other Stuff
}
if ((ocontrol.Name == (string)oDataRowView["ConName"]))
{
//Do stuff
}
else
{
//Do other Stuff
}
Please could someone explain the reason I still get a warning and the best practice way to deal with this?
These options will work:
if (Equals(ocontrol.Name, oDataRowView["ConName"])) // likely best option
if ((string)ocontrol.Name == oDataRowView["ConName"].ToString()) // assuming neither item is null
if (ocontrol.Name as string == oDataRowView["ConName"] as string) // assuming second item is actually a string
I am always confused about when to use if (sth == null). Design of delegate in C# is like this:
//Declaration:
private delegate void OnSthHappened();
//In some place, do:
OnSthHappened += SthHappendCallback;
//When use delegate:
if(OnSthHappened != null)
OnSthHappened();
I really think of judging it is null everytime when use OnSthHappened is unnecessary. I know that in compiler, delegate will become a class to handle the callback. Then why the C# compiler doesn't do the other way like:
//Use the delegate directly:
OnSthHappened();
//In the created-by-compiler class, do the judgement:
//object: instance object, Intptr method: a method pointer
if(method != 0x00) //Null, hide the judgement here
{
Invoke(object, method);
}
I just gave a scene of where to judge null, this is giving me hard choices everytime when I try to write API, to do ==null in caller or called functions? Does anyone could give me some style about where to use ==null judgement?
I know that in compiler, delegate will become a class to handle the callback
Delegate (more precise, MulticastDelegate, because in fact we work with multicast delegates) is a class already. The delegate keyword is just a way to declare a MulticastDelegate-derived type.
Where to use if(obj == null) When writing API?
Shortly, check for null:
in public or protected contacts, if the particular method parameter or return value must not be null. If it is null, throw an exception;
in public, protected or private contracts, when value the value could be null, and you can handle that.
public void Method1(Action action)
{
Contact.Requires<ArgumentNullException>(action != null);
}
public object Method2()
{
Contract.Ensures(Contract.Result<object>() != null);
// code here
}
public void Method2(Action action == null)
{
if (action != null)
action();
}
Do not check for null:
in private contacts, when value must not be null.
private void Method3()
{
var result = Method2();
// In case of result == null, NRE is a best option here.
Console.WriteLine(result.ToString().Length);
}
UPD.
why use different strategies between private and public methods? What is the benefit?
Public or protected surface is unpredictable.
You can't guarantee, that user of your class will provide, for example, valid parameter values. That's why you must check them - this is the way to tell the user, that something is wrong in his code. By delivering understandable exception, you can tell, what is wrong exactly. Note, that user hasn't access to your code, and ArgumentNullException on your method call is much more cleaner, that NullReferenceException inside of your method.
On the other hand, your release code should be clean from extra checks.
If you'll return null from any private method, and then try to access a member of that null value, you'll get NRE during debugging or testing. Then you have to fix error in your code and forget it. If you have fixed the error, there's no reason to keep the null-checking alive. This all doesn't avoid Debug.Assert/Contract.Assert or similar. But: a) those thing should live in debug version of your code; b) they must not be after every line of code, because this reduces code readability; c) often it is enough to catch an exception in debugger/unit test result.
In the following code:
MyObject objInstance;
private void someEventHandler(object sender, EventArgs e)
{
if (sender == objInstance && (sender as MyObject).SomeBoolProperty)
// Do Something
}
Resharper is warning that sender as MyObject may be a possible NullReferenceException. Is that possible given this code? I'm assuming that if sender == objInstance that (sender as MyObject) won't return null, but this wouldn't be the first time a Resharper message has informed me of a C# behavior/feature I was unaware of.
When you use as, null is returned if the object couldn't be converted (in this case, to MyObject). Therefore, your line (sender as MyObject) has the potential to be null.
This code can definitely cause a NullReferenceException to be thrown. Consider the case where objInstance and sender have the value null. In that case sender == objInstance will be true because null == null and hence the sender as MyObject will also return null and the code will throw on the property access
The best way to write that code would be
var senderObj = sender as MyObject;
if (senderObj != null &&
senderObj == objInstance &&
senderObj.SomeBoolProperty) {
// Do something
}
Unfortunately I don't believe there is a way to significantly simplify this code. There are 3 specific unrelated conditions you are attempting to express. Hence they must all be tested for
In this case you know that sender is really a MyObject. So use a simple cast instead of as:
if (sender == objInstance && ((MyObject)sender).SomeBoolProperty)
Or, even better:
if (sender == objInstance && objInstance.SomeBoolProperty)
The as operator returns null if your cast is not valid. If the Event sender is not of MyObject, (sender as MyObject) == null.
If objInstance is guaranteed to not be null, then your statement will never throw a NullReferenceException. However, it may throw if objInstance is null.
Since you can determine sender == objInstance, just operate on objInstance rather than casting sender, after verifying objInstance != null.
This is because R# isn't always the smartest. Also, you could still get a NullReferenceException if both sender and objInstance are null. Anyways, as you've established their equality, why not just use objInstance?
Try this instead:
if (sender == objInstance && objInstance.SomeBoolProperty)
To get rid of the squiggly:
MyObject objInstance;
private void someEventHandler(object sender, EventArgs e)
{
var myObj = sender as MyObject;
Debug.Assert(myObj != null);
if (sender == objInstance && myObj .SomeBoolProperty)
// Do Something
}
R# comprehends the assertion and will stop warning you. Also, it isn't such a bad practice to liberally insert these debugging assertions. Anytime you are receiving a reference type as an argument of a public method, I would assert that the value is not null, or in some cases throw an exception specifically for receiving a null parameter instead of waiting for the code to fail further down. It gets worse when that null is passed into other methods making it really difficult to know where and when the code will fail.