Reputation: 983
I'm writing a bit of code, and there is a part that gives me hassles. I'm having the following structure in my code:
foreach (Node node in nodes)
{
try
{
bool n = node.previous == null;
}
catch (Exception e)
{
StreamWriter s = new StreamWriter("error.txt");
s.WriteLine(e.Message);
s.WriteLine("-----------");
s.Close();
}
}
In here Node is a custom type, the node.prev variable is also a custom type (Location). Running this gives the following error-log:
Object reference not set to an instance of an object.
-----------
I'm 100% sure that node isn't null (which should be made impossible by foreach = Not true, sorry!). Also, as you can see in the following listing, the Node.previous is set to null at declaration:
public class Node
{
public Location previous = null;
public Location location;
public int distance;
...
...
}
I have no idea how I can fix these exeptions occuring, and I'm kind of at the end of having any ideas on how to solve this. Can anybody help me with this?
Note that these are all not the final code, but I sifted the parts that didn't matter!
Thanks in advance, Delpee
EDIT: Ricovox helped me to the solution with this answer, thanks a lot!
Upvotes: 0
Views: 2217
Reputation: 5223
So I'm posting another answer in response to your comment:
"I have checked for node being null, it isn't, at any point."
If that IS true, there here are some other options;
Take a look at the node.previous
class/struct definition. It COULD implement a CUSTOM ==
operator that throws an error when compared to null. As an example, think about the Nullable<T>
type. It has an overloaded ==
operator that returns true if the HasValue property is false (obviously, since it is a struct it isn't truly null, but overloading the operator gives the desired behavior.) To fix this, you could test object.ReferenceEquals(node.previous, null)
which wouldn't be overloaded. If you have access to change the node.previous
definition, perhaps you can find out why the overloaded operator throws an exception when compared to null (which it obviously shouldn't)
nodes
could be null, in which case it is the foreach statement that is throwing the error. Test nodes == null
before the foreach.
---------------Edit---------------
As Jeppe pointed out, my analogy with Nullable<T>
(in option #1, above) could be misleading (in fact it did confuse the discussion, although the point itself was correct). In order to better illustrate the idea of overriding the ==
operator, I've posted an example below that demonstrates the Container
type. This type is a struct, so it can never be null itself, but it contains a single Value object.
(The point of this struct is that you can work with any Container
object without worrying whether or not it is null, even though the contained Value
object might be null). The main thing to note is that when a Container is compared with ==
to null, the result will be true if Value
is null
, which would NOT be true if the ==
operator weren't overridden (because a struct can never be null).
public struct Container {
public object Value { get; set; }
public bool IsNull { get { return Value == null; } }
public static bool operator ==(Container x, object y) { return x.Equals(y); }
public static bool operator !=(Container x, object y) { return !x.Equals(y); }
public override bool Equals(object obj) {
if (obj is Container)
return Value == ((Container)obj).Value;
return Value == obj;
}
public override int GetHashCode() { return Value == null ? 0 : Value.GetHashCode(); }
}
////---------Test----------
var x = new Container { Value = null };
var y = new Container { Value = "hi" };
var z = new Container { Value = null };
Print(x == null); //true
Print(x == y); //false
Print(x == z); //true
And just in case you are wondering how overriding ==
would affect a class, I've written another example below that demonstrates a Box
class. It's similar to the Container
struct, except that we have to deal with the case in which the Box object is null itself. Note that in this case, there is another surprising result of overriding ==
. Two reference types can be equal (==
) to each other, even if they reference different objects, as long as they have equal Value
properties.
public class Box {
public static bool ItemsEqual(object x, object y) {
object xval, yval;
xval = x is Box ? (x as Box).Value : x;
yval = y is Box ? (y as Box).Value : y;
return xval == yval;
}
public object Value { get; set; }
public bool IsNull { get { return Value == null; } }
public static bool operator ==(Box x, object y) { return ItemsEqual(x, y); }
public static bool operator !=(Box x, object y) { return !ItemsEqual(x, y); }
public override bool Equals(object obj) { return ItemsEqual(this, obj); }
public override int GetHashCode() { return Value == null ? 0 : Value.GetHashCode(); }
}
////---------Test----------
object n = null;
Box w = null;
Box x = new Box { Value = null };
Box y = new Box { Value = "hi" };
Box z = new Box { Value = "hi" };
Print(w == null); //true (uses overridden '==' because w is defined as a Box)
Print(w == n); //true
Print(x == w); //true
Print(x == null); //true
Print(x == n); //true
Print(w == y); //false
Print(x == y); //false
Print(y == z); //true (actual ref's differ, but values are ==)
Upvotes: 4
Reputation: 61912
If nodes
were null
the exception would occur before the loop, and the exception wouldn't be caught.
Since the previous
member is a simple field, the only possibility I see is that one of the node
members of your nodes
collection is null
. You can do this:
foreach (Node node in nodes)
{
if (node == null)
throw new Exception("I told you so");
}
EDIT: OK, it turned out there was one possibility I didn't see, and that was a broken overload of the ==
operator. To make sure you call the usual overload, say:
foreach (Node node in nodes)
{
bool n = (object)(node.previous) == (object)null;
}
(actually it will suffice to cast just one side of the ==
operator to object
), or equivalently use ReferenceEquals
:
foreach (Node node in nodes)
{
bool n = object.ReferenceEquals(node.previous, null);
}
But you must fix the wrong implementation of the ==
overload.
If you had posted the stack trace of the exception in your original question, it would have been clear to most users here on SO that the exception came from a call to your ==
overload. So next time, inspect your stack trace.
Upvotes: 1
Reputation: 5223
The most likely problem is that node
is null!. There is nothing about the foreach statement that would prevent node
from being null, because in general an IEnumerable object (e.g. a list or collection) CAN contain null as a valid item.
No error would be thrown if previous
is null (unless the node.prev
class/struct overrides the ==
operator).
As others have mentioned, put in a test like this to verify:
foreach (Node node in nodes)
{
bool n;
try
{
if (node == null)
{
n = true; //do something to deal with a null node
}
else
{
n = node.previous == null;
}
}
catch (Exception e)
{
StreamWriter s = new StreamWriter("error.txt");
s.WriteLine(e.Message);
s.WriteLine("-----------");
s.Close();
}
}
Upvotes: 4
Reputation: 2500
I'm 100% sure that node isn't null
But I'm 100% sure that an element in nodes is null! try this:
foreach (Node node in nodes)
{
try
{
if(null == node) throw new Exception("This is not expected!");
bool n = node.previous == null;
}
catch (Exception e)
{
if(File.Exists("error.txt")) File.Delete("error.txt");
using(StreamWriter s = new StreamWriter("error.txt")){
s.WriteLine(e.Message);
s.WriteLine("-----------");
s.Close();}
}
}
Upvotes: 0
Reputation: 8459
There's nothing that ensures that node
is not null, since Node
is not a value type. Mind giving more details?
Upvotes: 0
Reputation: 36319
set a breakpoint at your line that starts with bool
and verify that node is not null and that nodes is not null. My guess is that either nodes is null, or else it contains a null value if it's not a type-safe list.
Upvotes: 0