Why does the C# compiler not even complain with a warning on this code? :
if (this == null)
{
// ...
}
Obviously the condition will never be satisfied..
Because you could override operator == to return true for that case.
public class Foo
{
public void Test()
{
Console.WriteLine(this == null);
}
public static bool operator ==(Foo a, Foo b)
{
return true;
}
public static bool operator !=(Foo a, Foo b)
{
return true;
}
}
Running new Foo().Test() will print "True" to the console.
The other question here is: why doesn't the compiler issue a warning for ReferenceEquals(this, null)? From the bottom of the above link:
A common error in overloads of operator == is to use (a == b), (a == null), or (b == null) to check for reference equality. This instead results in a call to the overloaded operator ==, causing an infinite loop. Use ReferenceEquals or cast the type to Object, to avoid the loop.
That might be answered by #Aaronaught's response. And that's also why you should be doing (object)x == null or ReferenceEquals(x, null), not doing a simple x == null, when you're checking for null references. Unless, of course, you're sure that the == operator is not overloaded.
Wow... I guess I was shamefully wrong
I disagree. I think you still make a good point.
The compiler knows whether the comparison is going to go to a user-defined comparison operator or not, and the compiler knows that if it does not, then 'this' is never null.
And in fact, the compiler does track whether a given expression can legally be null or not, in order to implement a minor optimization on non-virtual method calls. If you have a non-virtual method M and you say foo.M(); then the compiler generates this as "do a virtual call to M with receiver foo". Why? Because we want to throw if foo is null, and a virtual call always does a null check on the receiver. A non-virtual call does not; we'd have to generate it as "check foo for null, and then do a non-virtual call to M", which is longer, slower, more irritating code.
Now, if we can get away without doing the null check, we do. If you say this.M() or (new Foo()).M() then we do NOT generate a virtual call. We generate the non-virtual call without the null check because we know that it cannot be null.
So the compiler has excellent data on whether a particular comparison to null will sometimes, always, or never succeed.
The question then is "if the compiler knows that a particular comparison will never succeed, why not generate a warning for it?"
And the answer is "sometimes we do, and sometimes we don't".
We do in this situation:
int x = 123;
if (x == null) ...
There is an equality operator defined on two nullable ints. x is convertible to nullable int. null is convertible to nullable int. So that equality operator is valid, and therefore is used, and is of course always false. The compiler gives a warning that the expression is always false.
However, due to a bug we accidentally introduced in C# 3, this code does NOT produce that warning:
Guid x = whatever;
if (x == null) ...
Same deal. The nullable guid equality operator is valid, but the warning is suppressed. I'm not sure if we fixed this bug for C# 4 or not. If not, hopefully we'll get it into a service pack.
As for "if (this == null)" I don't know why we don't warn for that. It certainly seems like a good candidate for a warning. The most likely explanation is to follow this logical syllogism:
warnings are compiler features
compiler features must be (1) thought of, (2) designed, (3) implemented, (4) tested, (5) documented and (6) shipped to you before you can take advantage of the feature.
No one has done any of those six necessary things for this feature; we can't ship features that we never thought of in the first place.
therefore, no such feature.
There are infinitely many compiler features that we haven't thought of yet; we've implemented none of them.
Another reason to not give a warning here is that we try to give warnings on code which is both likely to be typed by accident and almost certainly wrong for a non-obvious reason. "this == null" is not likely to be typed in by accident, and though it is almost certainly wrong, as you note in the statement of your question, it is obviously wrong.
Compare that to our "guid == null" -- that is likely to happen by accident, because a developer might accidentally think that Guid is a reference type. Guids are usually passed around by reference in C++, so this is an easy mistake to make. The code is almost certainly wrong, but it is wrong in a non-obvious way. So this is a good candidate for a warning. (Which is why it is so unfortunate that this is a warning in C# 2 but not C# 3, due to a bug we introduced.)
Actually, the condition really can be satisfied, at least in Visual Studio 2008. They've fixed this behaviour in VS 2010, but it is not totally inconceivable that there might be another way to create such a condition.
(tl;dr version - in C# 3.5, it's legal to reference this from an anonymous function passed as a constructor argument, but if you actually try to use it, you'll find that this is null.)
Though the code below is a bastard it's still all C#. an if you call Bar you will get an InvalidOperationException with the message null.
public class Foo
{
static Action squareIt;
static Foo() {
var method = new DynamicMethod(
"TryItForReal",
typeof(void),
Type.EmptyTypes,
typeof(Foo).Module);
ILGenerator il = method.GetILGenerator();
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Call, typeof(Foo).GetMethod("tryit"));
il.Emit(OpCodes.Ret);
squareIt = (Action)method.CreateDelegate(typeof(Action));
}
public void tryit()
{
if (this == null) {
throw new InvalidOperationException("Was null");
}
}
public void Bar() {
squareIt();
}
}
This also falls in line with other warnings C# does (or not does for that matter) like:
if(true)
or
if(1 == 1)
These will also always have the same result no matter what.
Related
This question already has answers here:
Why do if statements in Unity3d C# allow objects that are not bools?
(2 answers)
Closed 4 years ago.
I use unity, the I try following code:
class C
{
}
void m()
{
var c = GetComponent<Collider>();
if (c)
{
}
var c2 = new C();
if (c2)
{
}
}
the Rider syntax check show:
if (c) syntax is correct and if (c2) raise syntax err, I hope if (c2) syntax right, how should i modify my class C
First off: the design of the unity library here is bad C# API design and you should not attempt to replicate it. It is not idiomatic in C# to check objects for nullity with if(c). You should always check for nullity with if (c != null) and you should design your objects to be checked for null like that.
The only time that you would typically enable if(c) style checking is if the object logically represents a Boolean without actually being a bool. For example, suppose you have a type SecurityCheck that represents whether a user passed a security check or not; you might have more information in an instance than just a bool, but you might want to be able to use it in contexts where a bool is expected.
In that case there are two ways to do it.
If an instance can be converted to bool then you write a user-defined implicit conversion to bool.
If you want to preserve the content of the instance in custom implementations of & and | then you should provide custom implementations of operators |, &, true and false. If you do so then if, while, and so on, will use operator true to determine if the condition is met.
But again: do not emulate the design of Unity here. Do not make conversions to bool that just check nullity. That's not the way we check for nullity in C#. If you want to check for null you should write a null check.
Readability should always be a higher priority so doing checks like if(c != null) or if(c == null) aren't a bad thing(They are a good thing), it shows that you meant to enter that function specifically for those circumstance were if(!c) can sometimes be misinterpreted because someone misses ! but to answer your question you can change your Class C to this:
class C
{
public static implicit operator bool(C obj)
{
return obj != null;
}
}
Be aware though, that just because you can if(collider) an object does not necessarily mean that implicit conversion means it isn't null it can mean something else. In the example code I posted it does check if the object isn't null.
The check you have shown for c2 will not work in C# (as opposed to, for example, Javascript).
Instead, you have to explicitly test against null. Or you can use the null-conditional operators.
All of the following variants will prevent NullReferenceException when calling DoSomething().
Check for null and throw:
if (c2 == null) {
throw new ArgumentNullException(nameof(c2));
}
c2.DoSomething();
Check for not null and do work:
if (c2 != null) {
c2.DoSomething();
}
Use null-conditional operator:
c2?.DoSomething(); // will do nothing if c2 is null
I would check the null state of c2 by simply using:
if (c2 != null)
This is standard, clear, and concise.
We often like to make our code ever more concise, hence trying to simplify the logic down to if (c2), but it's not clear that the object returned from the C() constructor can be implicitly converted to a bool. Even if a C object could be implicitly converted to a bool, that would be uncommon, and so programmers who come along after you might wonder why/how you're checking whether the object is null that way.
To take this case even further, I would check for the null state of c in the same way instead of relying on GetComponent<Collider>() to return a bool. Often, clarity is preferred over brevity.
The following extension method tries, for a given value of unknown type, to find a constructor with a single parameter such that the constructor can be called with that value.
private static ConstructorInfo ConstructorThatTakesValue
(this Type thisType, object value)
{
return thisType.GetConstructors().FirstOrDefault(c =>
c.GetParameters().Count() == 1 &&
c.GetParameters().First().ParameterType.IsAssignableFrom(value.GetType()));
}
That is, if var c = typeof(X).ConstructorThatTakesValue(y), then we can create a x by
var x = (X)c.Invoke(new object[] { y });
The code above works like a charm, but Resharper marks the line containing IsAssignableFrom and displays "Use method InstanceOfType". It also provides a QuickFix which literally just replaces IsAssignableFrom by IsInstanceOfType, which by my intuition is the exact opposite of what I am trying to achieve:
c.GetParameters().First().ParameterType.IsInstanceOfType(value.GetType()));
Even more suspicious, this message is displayed as a "suggestion", not a warning or so. That is, Resharper seems to consider the change a simple stylistic improvement.
I also tried to gain understanding of the semantics of the two methods, but I was not able to grasp the meaning of documentation on the MSDN either. My understanding would be that if class A : B, then B.GetType().IsAssignableFrom(A.GetType()) and A.GetType().IsInstanceOfType(B.GetType()).
One works with Types and the Other instances, in fact one calls the other:
public virtual bool IsInstanceOfType(object o)
{
if (o == null)
{
return false;
}
return this.IsAssignableFrom(o.GetType());
}
Kevin Cooks answer is good, but there is an overlook in Resharper's engine: it does not differenciate from Objects and Types (it treat the Type instance as an Object).
As in, if your B argument is already a Type object, it will still ask you to switch to "IsInstanceOf". Which is false and will lead to errors in this very limited context.
EDIT: I double check my test case I founf out it's not longer the case. When the second argument type is indeed Type, it correctly uses the IsAssignableFrom method without warnings.
I've recently been coding a lot in both Objective C while also working on several C# projects. In this process, I've found that I miss things in both directions.
In particular, when I code in C# I find I miss the short null check syntax of Objective C.
Why do you suppose in C# you can't check an object for null with a syntax like:
if (maybeNullObject) // works in Objective C, but not C# :(
{
...
}
I agree that if (maybeNullObject != null) is a more verbose / clear syntax, but it feels not only tedious to write it out in code all the time but overly verbose. In addition, I believe the if (maybeNullObject) syntax is generally understood (Javascript, Obj C, and I assume others) by most developers.
I throw this out as a question assuming that perhaps there is a specific reason C# disallows the if (maybeNullObject) syntax. I would think however that the compiler could easily convert an object expression such as if (maybeNullObject) automatically (or automagically) to if (maybeNullObject != null).
Great reference to this question is How an idea becomes a C# language feature?.
Edit
The short null check syntax that I am suggesting would only apply to objects. The short null check would not apply to primitives and types like bool?.
Because if statements in C# are strict. They take only boolean values, nothing else, and there are no subsequent levels of "truthiness" (i.e., 0, null, whatever. They are their own animal and no implicit conversion exists for them).
The compiler could "easily convert" almost any expression to a boolean, but that can cause subtle problems (believe me...) and a conscious decision was made to disallow these implicit conversions.
IMO this was a good choice. You are essentially asking for a one-off implicit conversion where the compiler assumes that, if the expression does not return a boolean result, then the programmer must have wanted to perform a null check. Aside from being a very narrow feature, it is purely syntactic sugar and provides little to no appreciable benefit. As Eric Lippert woudl say, every feature has a cost...
You are asking for a feature which adds needless complexity to the language (yes, it is complex because a type may define an implicit conversion to bool. If that is the case, which check is performed?) only to allow you to not type != null once in a while.
EDIT:
Example of how to define an implicit conversion to bool for #Sam (too long for comments).
class Foo
{
public int SomeVar;
public Foo( int i )
{
SomeVar = i;
}
public static implicit operator bool( Foo f )
{
return f.SomeVar != 0;
}
}
static void Main()
{
var f = new Foo(1);
if( f )
{
Console.Write( "It worked!" );
}
}
One potential collision is with a reference object that defines an implicit conversion to bool.
There is no delineation for the compiler between if(myObject) checking for null or checking for true.
The intent its to leave no ambiguity. You may find it tedious but that short hand is responsible for a number of bugs over the years. C# rightly has a type for booleans and out was a conscience decision not to make 0 mean false and any other value true.
You could write an extension method against System.Object, perhaps called IsNull()?
Of course, that's still an extra 8 or 9 characters on top of the code you'd have to write for the extension class. I think most people are happy with the clarity that an explicit null test brings.
In C, in order to test if a pointer is null we can do:
if (p != NULL)
if (p != 0)
if (p)
Why isn't there any equivalent in C# that would allow us to do the following?
if (object)
instead of
if (object != null)
Because tests of that nature could lead to unexpected bugs in programs, thus they favored requiring boolean expressions to be explicit (as did Java), instead of performing an implicit conversion to bool.
This is also the same reason why you cannot use an int as a boolean expression in C#. Since the only valid boolean expressions are expressions that evaluate directly to bool, this keeps unexpected errors from being introduced in the code, such as the old C gotcha:
if (x = 5)
{
// always true
}
So, in short, it was not included in order to favor readability and explicitness. Yes, it does come at a slight cost in brevity, but the gains in reduction of unexpected bugs more than make up for the cost of hainvg to add != null inside the parenthesis...
(You can, of course, create an implicit conversion of a custom type to bool, as a workaround, but you can't globally apply that to any object type)
Why isn't there any equivalent in C# that would allow us to do the following?
In order to be used a feature must first be:
thought of
designed
specified
approved
implemented
tested
shipped
The feature you mention has been thought of. It has not been designed, specified or approved by the design committee, it has not been implemented by the development team, it has not been tested, and it has never shipped in any product. Therefore you cannot use the feature.
If that doesn't answer your question then ask a better question. Asking why a language doesn't have a feature is like asking why a box is empty. Every empty box is empty for the same reason: because there's nothing in it. Every unavailable feature is unavailable because it was never shipped to customers, and there's not much more to say about it.
Technically speaking it doesn't work because there is no implicit conversion possible from your custom object class to bool (boolean). As long as you provide an implicit conversion operator, that might check your object for null, you can go ahead with your syntax:
public static implicit operator bool(MyType p)
{
return (p != null) && (p != 0);
}
Integrating the suggestion by Dan Bryant:
An alternative way is to implement implicit "true" and "false" operators for your data type. You might need this if your type allow tri-state evaluation to bool: true, false and null. This is quite a common case in databases where the null value designates missing data. Here is an example from the MSDN webpage:
public static bool operator true(DBBool x)
{
return x.value > 0;
}
public static bool operator false(DBBool x)
{
return x.value < 0;
}
Because that's how the language designers designed the language. Partially it's to prevent dumb mistakes like:
if (p = 42)
Because an Object is not a Pointer, it is an Object.
Because it is not in C# specification and the compiler does not understand such expression.
And if you are after the reason why it is not used in this way in C# - from my point of view it is totally illogical to check something for null in a manner if(object).
If object what?
Your example looks readable only because your object is named 'object'. In reality objects have names that derive from their use/function. If your object was called 'validatedWidget' then your code would look like
if (validatatedWidget)
{
// do something
}
Which would incorrectly imply something where as:
if (validatedWidget != null)
{
// do something
}
Is far more explicit, and is hardly a lot of work.
Syntax of if statement is ::
if(condition)
and the result of condition should be boolean i.e. true or false.
So we do write any condition like
x = 10;
if(x == 10)
but if(object) does not make a specific condition to result out as a boolean result.
if we write
boolean object = true;
if(object)
then it will be perfectly fine.
but to see if any object is null or not we can't write if(object) we need to write it as if(object == null) or if(object != null), because such conditions will result in boolean result.
I have a property in a composite control that checks to see if the value has changed prior to actually setting the related private field and doing a few other things.
However, it appears that it is never evaluating the statement.
Here is the code for the property:
public T SearchCriteria
{
get
{
return mySearchCriteria;
}
set
{
if (value != mySearchCriteria)
{
mySearchCriteria = value;
EnsureChildControls();
SearchGridParser parser = SearchGridParserFactory.GetParser(this.Type);
parser.SetSearchPanelControls<T>(this.mySearchCriteria, ref mySearchParametersPanel);
GridView.PageIndex = 0;
}
}
}
I have stepped through the code, and everytime it gets to "value != mySearchCriteria" it evaluates to false and skips the code inside the if statement. In fact, it does this even when I change it to "value == mySearchCriteria".. if just completely skips it no matter how it evaluates!
What the hey?
I've tried changing the order of the arguments in the check, and also using object.Equals() but none of these changes have made any difference.
I have overridden Equals, !=, == and GetHashCode.
There are other places in the code where it uses the "==" and "!=" for these object types without a problem, so I know that my overriding is working correctly.
Problem is, this never even hits the overriden methods. I put breaks on "==", "!=", "Equals" and "GetHashCode" and none of them are being called when the "value != mySearchCriteria" statement is being evaluated.
It's like it completely skips evaluating it.
Using == between generic types is almost always a bad idea. Operators are overloaded rather than overridden, so even if there is an == operator on your actual types, the compiler won't know about it. (That means your claim that you've "overridden" == and != is already incorrect - you've overloaded those operators. You should make sure you understand the difference, as it's very important.)
When you write:
There are other places in the code where it uses the "==" and "!=" for these object types without a problem, so I know that my overriding is working correctly.
I suspect those areas aren't in generic code... they're where the compiler knows what types are being compared, so knows to use your overloads. That's very different from your generic situation, where the compiler doesn't know what to use for ==, so falls back to reference identity.
I assume you have a generic constraint of where T : class or your code wouldn't compile at all - but it's still just going to perform a reference comparison, instead of using whatever overload is provided by the actual type of T.
Use EqualityComparer.Default<T>.Equals(value, mySearchCriteria) to use overridden implementations of Equals including IEquatable<T>.