I just got into a debate with one of my coworkers about checking for null values.
He SWEARS that "in certain situations" the code below would give him a null value exception:
string test = null;
if(test == null) //error here
{
}
but that if changed the code to this there would be no error:
string test = null;
if(null == test) //NO error here
{
}
I told him there was no way this could happen but he swears it fixed his code. Is there any possible situation where the above change could fix an error?
Not with string, no. You could do so with a badly written == overload though:
using System;
public class NaughtyType
{
public override int GetHashCode()
{
return 0;
}
public override bool Equals(object other)
{
return true;
}
public static bool operator ==(NaughtyType first, NaughtyType second)
{
return first.Equals(second);
}
public static bool operator !=(NaughtyType first, NaughtyType second)
{
return !first.Equals(second);
}
}
public class Test
{
static void Main()
{
NaughtyType nt = null;
if (nt == null)
{
Console.WriteLine("Hmm...");
}
}
}
Of course, if you changed the equality operator to this:
public static bool operator ==(NaughtyType first, NaughtyType second)
{
return second.Equals(first);
}
then your colleagues code would fail, but yours wouldn't! Basically if you overload operators properly - or use types which don't overload operators - this isn't a problem. If your colleague keeps claiming he's run into it, ask him to reproduce it. He certainly shouldn't be asking you to reduce readability (I believe most people find the first form more readable) on the basis of something he can't demonstrate.
I think this is a left-over from a 'best practice' in C/C++, because using '=' instead of '==' is an easy to make mistake:
if(test = null) // C compiler Warns, but evaluates always to false
if(null = test) // C compiler error, null cannot be assigned to
In C#, they both produce an error.
You're right. If he can reproduce this without an overloaded == operator, invite him to post it here.
The test of if (test == null) if test is a string is valid and will never give an exception. Both tests are also essentially exactly the same.
Related
I know this might seem impossible at first and it seemed that way to me at first as well, but recently I have seen exactly this kind of code throw a NullReferenceException, so it is definitely possible.
Unfortunately, there are pretty much no results on Google that explain when code like foo == null can throw a NRE, which can make it difficult to debug and understand why it happened. So in the interest of documenting the possible ways this seemingly bizarre occurrence could happen.
In what ways can this code foo == null throw a NullReferenceException?
in C# you can overload operators to add custom logic on some comparison like this. For example:
class Test
{
public string SomeProp { get; set; }
public static bool operator ==(Test test1, Test test2)
{
return test1.SomeProp == test2.SomeProp;
}
public static bool operator !=(Test test1, Test test2)
{
return !(test1 == test2);
}
}
then this would produce a null reference exception:
Test test1 = null;
bool x = test1 == null;
One example is with getters:
class Program
{
static void Main(string[] args)
{
new Example().Test();
}
}
class Example
{
private object foo
{
get => throw new NullReferenceException();
}
public void Test()
{
Console.WriteLine(foo == null);
}
}
This code will produce a NullReferenceException.
While quite esoteric, it is possible to cause this type of behavior via custom implementations of DynamicMetaObject. This would be a rare but interesting example of where this could occur:
void Main()
{
dynamic foo = new TestDynamicMetaObjectProvider();
object foo2 = 0;
Console.WriteLine(foo == foo2);
}
public class TestDynamicMetaObjectProvider : IDynamicMetaObjectProvider
{
public DynamicMetaObject GetMetaObject(Expression parameter)
{
return new TestMetaObject(parameter, BindingRestrictions.Empty, this);
}
}
public class TestMetaObject : DynamicMetaObject
{
public TestMetaObject(Expression expression, BindingRestrictions restrictions)
: base(expression, restrictions)
{
}
public TestMetaObject(Expression expression, BindingRestrictions restrictions, object value)
: base(expression, restrictions, value)
{
}
public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
{
// note it doesn't have to be an explicit throw. Any improper property
// access could bubble a NullReferenceException depending on the
// custom implementation.
throw new NullReferenceException();
}
}
Not literally your code, but awaiting a null task will also throw:
public class Program
{
public static async Task Main()
{
var s = ReadStringAsync();
if (await s == null)
{
Console.WriteLine("s is null");
}
}
// instead of Task.FromResult<string>(null);
private static Task<string> ReadStringAsync() => null;
}
Do note however that the debugger can get the location of throwing statements wrong. It might show the exception thrown at the equality check, while it occurs at earlier code.
foo == null does indeed to operator overload resolution, and the operator in question didn't handle being passed a null. We are starting to consider writing foo == null obsolete and preferring (taking a page from Visual Basic) foo is null or !(foo is null) which is soon to be full is not null to explicitly inline a null pointer check.
Fix your operator== implemenation. It shouldn't throw, but it is.
Lets start with:
using System;
public class Program
{
class A
{
public virtual void Do() { }
}
class B:A
{
}
public static void Main()
{
var m1 = typeof(A).GetMethod("Do");
var m2 = typeof(B).GetMethod("Do");
Console.WriteLine("Methods are equal?\t\t{0}", m1 == m2);
Console.WriteLine("Method handles are equal?\t{0}", m1.MethodHandle == m2.MethodHandle);
Console.WriteLine("Done.");
Console.ReadKey();
}
}
(try it online at ideone)
So, there are two unequal MethodInfo instances, both containing the same method handle. Here's the equals operator source:
public static bool operator ==(MethodInfo left, MethodInfo right)
{
if (ReferenceEquals(left, right))
return true;
if ((object)left == null || (object)right == null ||
left is RuntimeMethodInfo || right is RuntimeMethodInfo) // <----???
{
return false;
}
return left.Equals(right);
}
It doesn't look like an accidental bug, at least until there was assumption that all instances of RuntimeMethodInfo are cached and there newer will be two different instances for the same method. In that case something is broken, obviously.
Any reasons behind this behavior, anyone?
P.S. Do not mark as a [duplicate], please:) The question is not about 'how to compare?'. That one was answered multiple times, here and here for example.
Thanks!
I believe your assumption for the reasoning behind it - that two RuntimeMethodInfo instances can be compared by reference equality - is correct. Your assumption that it's broken isn't correct though.
The two MethodInfo objects here are different, as they have different ReflectedType properties:
Console.WriteLine(m1.ReflectedType); // Program+A
Console.WriteLine(m2.ReflectedType); // Program+B
Can this code return null?
(this.Result == Result.OK)
Can this line (or a similar one) return anything except than true or false (e.g. null)?
(this.Result == Result.OK)
OK; let's take this piece by piece:
this.(anything)
That can fail if this is null - which it never should be, but theoretically can be if you are evil - so we could fail with a NullReferenceException.
this.Result
if that is a property accessor (a get), then it could fail in any way it likes - it could throw an exception.
Result.OK
now; if this is an enum, it is just a ldc - but if this .OK is actually a static property accessor, it can certainly fail with any exception it likes.
this.Result == Result.OK
We need to know what .Result returns; if we assume that it returns a Result (we don't know that), then we still need to know what Result is: if it is an enum it'll be a direct numeric equality check; if it is a nullable-enum, "lifted" equality rules apply, but still resolve cleanly. If it is a custom type that overloads ==, then anything could happen and any exception could result.
But here's the crazy: == does not need to return a bool:
public static int operator ==(int x, Foo foo)
{
return 0; // DO NOT EVER DO THIS
}
public static int operator !=(int x, Foo foo)
{
return 0; // DO NOT EVER DO THIS
}
If you the Result type is custom, then (this.Result == Result.OK) can return anything it wants:
using System;
class P
{
static void Main()
{
new P().Test();
}
public Result Result { get; set; }
public void Test()
{
var x = (this.Result == Result.OK);
Console.WriteLine(x.GetType().Name); // Int32
}
}
public class Result
{
public static Result OK { get { return null; } }
public static int operator ==(Result x, Result y)
{
return 42; // DO NOT EVER DO THIS
}
public static int operator !=(Result x, Result y)
{
return 0; // DO NOT EVER DO THIS
}
}
Finally, we need to consider that something obscure like a ThreadAbortException, OutOfMemoryException or StackOverflowException could happen at any time.
But in sane conditions: yes, it can only result in a bool result.
As == is comparison operator,this statement always return a Bool
The == operator will return true or false at all times. That is a boolean.
It should be noted that the "or another" in your question can indeed return something other than true or false. Unless you tell us what the other you have in mind is we can't answer that.
This answer assumes that the expression does return something. As Marc Gravell points out exceptions may stop it returning at all (depending on how you consider returning).
Also Marc kindly pointed out that == can be overloaded. It is almost certainly a bad idea to do so and change the return type but it seems it is theoretically possible.
No, == can only returns true or false.
The statement itself will return a bool true or false.
The object involved:
this.Result
Could potentially be null, perhaps this is what you're referring to when you ask whether it can return null
There are 2 possible outcomes.
The line is executed and returns true
the line is executed and it returns false
I have next code:
private T CreateInstance<T>(object obj) // where T : ISomeInterface, class
{
...
if (!typeof(T).IsAssignableFrom(obj.GetType())) { throw ..; }
return (T)obj;
}
Can it be replaced with this:
T result = obj as T;
if (result == null) { throw ..; }
return result;
If not - why?
What about if (!(bar is T)) { throw ..; }
Alternatively if you don't need your own exception message the simplest answer is just to do:
return (T)obj;
The reason if that if it's not castable an InvalidCastException will be thrown and the return ignored. Unless you're adding some more logic or a custom error message there's no need to do a check and throw your own exception.
Another variant:
private T CreateInstance<T>(object obj) where T : ISomeInterface // as OP mentioned above
{
...
T result = obj as T;
if (result == null)
{ throw ..; }
else
return result;
}
Yes you can use your as operator code there instead of the original code, so long as T is a reference type or nullable.
as is the recommended way of casting in C# (see item 3 of Effective C#, by Bill Wagner)
From system.type.isassignablefrom:
[returns] true if c and the current Type represent the same type, or if the current Type is in the inheritance hierarchy of c, or if the current Type is an interface that c implements, or if c is a generic type parameter and the current Type represents one of the constraints of c. false if none of these conditions are true, or if c is null.
From 7.10.11 of the C# spec:
In an operation of the form E as T, E must be an expression and T must be a reference type, a type parameter known to be a reference type, or a nullable type
So you can see that they do comparable checks.
Maybe this (less brackets, better readability)
if (obj is T)
{
return (T)obj;
}
else
throw new ...
EDITED
by reduced number of brackets I originally meant inverted check: ie
if (obj is T)
instead of
if (!(obj is T))
so final version can be
if (obj is T)
{
return (T)obj;
}
throw new ...
or
if (obj is T)
{
return (T)obj;
}
else
{
throw new ...
}
See this post
The second one is safe...because at the first one if obj is null you will get exception (obj.GetType() --> NullReferenceException).
When you place "is" and then "as" is cause performance issues..
The class constraint where T : class allows you to use the as T statement.
private T CreateInstance<T>(object obj) where T : class
{
if (!(obj is T)) { throw new ArgumentException("..."); }
return obj as T;
}
or
private T CreateInstance<T>(object obj)
{
if (!(obj is T)) { throw new ArgumentException("..."); }
return (T)obj;
}
You're probably looking for the is keyword, with the syntax expression is type
Documentation describes it as performing the checks you want:
An is expression evaluates to true if
both of the following conditions are
met:
• expression is not null.
• expression
can be cast to type. That is, a cast
expression of the form
(type)(expression) will complete
without throwing an exception.
Edit
However, if instead of just working out whether you can cast something before you try, the as keyword is probably your best solution as you describe in your post.
The following code would perform the same function though...
try
{
T result = (T)obj;
return result;
}
catch (InvalidCastException ex)
{
// throw your own exception or deal with it in some other way.
}
Which method you prefer is up to you...
IsAssignableFrom used by this scene:
foreach (PropertyInfo property in GetType().GetProperties())
{
if (typeof(SubPresenter).IsAssignableFrom(property.PropertyType))
{//Do Sth.}
}
Just for the developers who like to play the numbers game (who doesn't!).
Below you'll find a performance comparison test for IsAssignableFrom vs. As. Of course this will only count if you have an instance.
The result of the test (one million attempts):
IsAssignableFrom: 146 ms elapsed
AsOperator: 7 ms elapsed
[TestMethod]
public void IsAssignableFromVsAsPerformanceTest()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int attempts = 1000000;
string value = "This is a test";
for (int attempt = 0; attempt < attempts; attempt++) {
bool isConvertible = typeof(IConvertible).IsAssignableFrom(value.GetType());
}
stopwatch.Stop();
Console.WriteLine("IsAssignableFrom: {0} ms elapsed", stopwatch.ElapsedMilliseconds);
stopwatch.Restart();
for (int attempt = 0; attempt < attempts; attempt++) {
bool isConvertible = value as string != null;
}
stopwatch.Stop();
Console.WriteLine("AsOperator: {0} ms elapsed", stopwatch.ElapsedMilliseconds);
}
It may have been intended to handle cases where a conversion constructor would allow the operation, but apparently IsAssignableFrom doesn't handle that either. Don't see anything that can handle that. So I don't see how to check for cases like this:
class Program
{
static void Main(string[] args)
{
B bValue = new B(123);
Console.WriteLine(typeof(A).IsAssignableFrom(bValue.GetType()));
//Console.WriteLine(bValue is A);
//Console.WriteLine(bValue as A == null);
A aValue = bValue;
Console.WriteLine(aValue.ToString());
}
}
class A
{
string value;
public A(string value)
{
this.value = value;
}
public override string ToString()
{
return value;
}
}
class B
{
int value;
public B(int value)
{
this.value = value;
}
public static implicit operator A(B value)
{
return new A(value.value.ToString());
}
}
In the end, I don't see any reason why you wouldn't want to use your version of the code, unless you want the code to throw an exception when obj is null. That's the only difference I can see. obj.GetType() will throw an null reference exception when obj is null instead of throwing the specified exception.
Edit: I see now your version of the code will not compile if T can be a value type, but the other suggested solution like "if (obj is T) return (T)obj;" will compile. So I see why your suggested alternative will not work, but I don't see why you couldn't use "is".
Or even better because its easer to read true conditionals.
if(obj is T){
//Create instance.
}
else{
throw new InvalidArgumentException("Try Again");
}
Currently I have this (edited after reading advice):
struct Pair<T, K> : IEqualityComparer<Pair<T, K>>
{
readonly private T _first;
readonly private K _second;
public Pair(T first, K second)
{
_first = first;
_second = second;
}
public T First { get { return _first; } }
public K Second { get { return _second; } }
#region IEqualityComparer<Pair<T,K>> Members
public bool Equals(Pair<T, K> x, Pair<T, K> y)
{
return x.GetHashCode(x) == y.GetHashCode(y);
}
public int GetHashCode(Pair<T, K> obj)
{
int hashCode = obj.First == null ? 0 : obj._first.GetHashCode();
hashCode ^= obj.Second == null ? 0 : obj._second.GetHashCode();
return hashCode;
}
#endregion
public override int GetHashCode()
{
return this.GetHashCode(this);
}
public override bool Equals(object obj)
{
return (obj != null) &&
(obj is Pair<T, K>) &&
this.Equals(this, (Pair<T, K>) obj);
}
}
The problem is that First and Second may not be reference types (VS actually warns me about this), but the code still compiles. Should I cast them (First and Second) to objects before I compare them, or is there a better way to do this?
Edit:
Note that I want this struct to support value and reference types (in other words, constraining by class is not a valid solution)
Edit 2:
As to what I'm trying to achieve, I want this to work in a Dictionary. Secondly, SRP isn't important to me right now because that isn't really the essence of this problem - it can always be refactored later. Thirdly, comparing to default(T) will not work in lieu of comparing to null - try it.
Your IEqualityComparer implementation should be a different class (and definately not a struct as you want to reuse the reference).
Also, your hashcode should never be cached, as the default GetHashcode implementation for a struct (which you do not override) will take that member into account.
It looks like you need IEquatable instead:
internal struct Pair<T, K> : IEquatable<Pair<T, K>>
{
private readonly T _first;
private readonly K _second;
public Pair(T first, K second)
{
_first = first;
_second = second;
}
public T First
{
get { return _first; }
}
public K Second
{
get { return _second; }
}
public bool Equals(Pair<T, K> obj)
{
return Equals(obj._first, _first) && Equals(obj._second, _second);
}
public override bool Equals(object obj)
{
return obj is Pair<T, K> && Equals((Pair<T, K>) obj);
}
public override int GetHashCode()
{
unchecked
{
return (_first != null ? _first.GetHashCode() * 397 : 0) ^ (_second != null ? _second.GetHashCode() : 0);
}
}
}
If you use hashcodes in comparing methods, you should check for "realy value" if the hash codes are same.
bool result = ( x._hashCode == y._hashCode );
if ( result ) { result = ( x._first == y._first && x._second == y._second ); }
// OR?: if ( result ) { result = object.Equals( x._first, y._first ) && object.Equals( x._second, y._second ); }
// OR?: if ( result ) { result = object.ReferenceEquals( x._first, y._first ) && object.Equals( x._second, y._second ); }
return result;
But there is littlebit problem with comparing "_first" and "_second" fields.
By default reference types uses fore equality comparing "object.ReferenceEquals" method, bud they can override them. So the correct solution depends on the "what exactly should do" the your comparing method. Should use "Equals" method of the "_first" & "_second" fields, or object.ReferenceEquals ? Or something more complex?
Regarding the warning, you can use default(T) and default(K) instead of null.
I can't see what you're trying to achieve, but you shouldn't be using the hashcode to compare for equality - there is no guarantee that two different objects won't have the same hashcode. Also even though your struct is immutable, the members _first and _second aren't.
First of all this code violates SRP principle. Pair class used to hold pairs if items, right? It's incorrect to delegate equality comparing functionality to it.
Next let take a look at your code:
Equals method will fail if one of the arguments is null - no good. Equals uses hash code of Pair class, but take a look at the definition of GetHashCode, it just a combination of pair members hash codes - it's has nothing to do with equality of items. I would expect that Equals method will compare actual data. I'm too busy at the moment to provide correct implementation, unfortunately. But from the first look, you code seems to be wrong. It would be better if you provide us description of what you want to achieve. I'm sure SO members will be able to give you some advices.
Might I suggest the use of Lambda expressions as a parameter ?
this would allow you to specify how to compare the internal generic types.
I don't get any warning when compiling about this but I assume you are talking about the == null comparison? A cast seems like it would make this all somewhat cleaner, yes.
PS. You really should use a separate class for the comparer. This class that fills two roles (being a pair and comparing pairs) is plain ugly.