我正在写一些代码,有一部分让我烦恼。 我的代码中有以下结构:
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();
}
}
此处Node是自定义类型,node.prev变量也是自定义类型(Location)。运行此命令会显示以下错误日志:
Object reference not set to an instance of an object.
-----------
我100%确定该节点不为空(应该通过foreach使其不可能 =不是,抱歉!)。此外,如下面的清单所示,Node.previous在声明时设置为null:
public class Node
{
public Location previous = null;
public Location location;
public int distance;
...
...
}
我不知道如何解决这些出现的问题,而且我对如何解决这个问题有任何想法。有人可以帮我吗?
请注意,这些都不是最终的代码,但我筛选了无关紧要的部分!
提前致谢, Delpee
编辑:Ricovox帮我解决了this answer的问题,非常感谢!
答案 0 :(得分:4)
最可能的问题是node
是 null!。 foreach语句没有任何内容可以阻止node
为空,因为通常IEnumerable对象(例如列表或集合) CAN 包含null作为有效项。
如果previous
为null,则不会抛出任何错误(除非node.prev
类/结构覆盖==
运算符)。
正如其他人所提到的那样,进行这样的测试来验证:
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();
}
}
答案 1 :(得分:4)
所以我在回复你的评论时发布了另一个答案:
“我已经检查过节点是否为null,它在任何时候都没有。”
如果这是真的,那么还有其他一些选择;
查看node.previous
类/结构定义。它可以实现一个CUSTOM ==
运算符,与null相比,它会抛出一个错误。例如,考虑Nullable<T>
类型。它有一个重载的==
运算符,如果HasValue属性为false,则返回true(显然,因为它是一个结构,它不是真正的null,但重载运算符会产生所需的行为。)为了解决这个问题,你可以测试object.ReferenceEquals(node.previous, null)
哪个不会超载。如果您有权更改node.previous
定义,也许您可以找出为什么重载运算符在与null(显然不应该)相比时抛出异常
nodes
可以为null,在这种情况下,它是抛出错误的foreach语句。在foreach之前测试nodes == null
。
<强> ---------------编辑--------------- 强>
正如Jeppe指出的那样,我与Nullable<T>
的比喻(在上面的选项#1中)可能会产生误导(实际上它确实混淆了讨论,尽管这一点本身是正确的)。为了更好地说明覆盖==
运算符的想法,我在下面发布了一个演示Container
类型的示例。这种类型是一个结构,因此它本身永远不能为null,但它包含一个Value对象。
(这个结构的要点是你可以使用任何Container
对象而不用担心它是否为null,即使包含的Value
对象可能为null)。需要注意的主要事项是,当一个Container与==
进行比较为null时,如果Value
为null
,则结果为true,如果==
则不为真运算符未被覆盖(因为结构永远不能为空)。
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
如果你想知道覆盖==
将如何影响一个类,我在下面写了另一个演示Box
类的例子。它类似于Container
结构,除了我们必须处理Box对象本身为null的情况。请注意,在这种情况下,覆盖==
还有另一个令人惊讶的结果。两个引用类型可以相互相等(==
),即使它们引用不同的对象,只要它们具有相同的Value
属性。
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 ==)
答案 2 :(得分:1)
如果nodes
为null
,则在循环之前会发生异常,并且不会捕获异常。
由于previous
成员是一个简单的字段,我看到的唯一可能性是node
集合中的nodes
个成员之一是null
。你可以这样做:
foreach (Node node in nodes)
{
if (node == null)
throw new Exception("I told you so");
}
编辑:好的,事实证明我有一种可能性没有看到,这是==
运算符的重载。为了确保你调用通常的过载,请说:
foreach (Node node in nodes)
{
bool n = (object)(node.previous) == (object)null;
}
(实际上只需将==
运算符的一侧强制转换为object
),或等效地使用ReferenceEquals
:
foreach (Node node in nodes)
{
bool n = object.ReferenceEquals(node.previous, null);
}
但必须修复==
重载的错误实现。
如果您在原始问题中发布了异常的堆栈跟踪,那么大多数用户都可以清楚地看到异常来自对==
重载的调用。所以下次检查堆栈跟踪。
答案 3 :(得分:0)
没有什么可以确保node
不为空,因为Node
不是值类型。介意提供更多细节?
答案 4 :(得分:0)
在您的行中设置以bool
开头的断点,并验证该节点不为空且该节点不为空。我的猜测是两个节点都是null,否则它包含一个空值,如果它不是一个类型安全的列表。
答案 5 :(得分:0)
我100%确定该节点不为空
但我100%确定节点中的元素为空!试试这个:
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();}
}
}