0

我正在编写一些代码,其中有一部分给我带来了麻烦。我的代码中有以下结构:

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;
    ...
    ...
}

我不知道如何解决发生的这些异常,而且我对如何解决这个问题有任何想法。有人可以帮我吗?

请注意,这些都不是最终代码,但我筛选了无关紧要的部分!

在此先感谢,德尔皮

编辑:Ricovox 帮助我解决了这个问题,非常感谢!

4

6 回答 6

4

最可能的问题是node null !。foreach 语句没有任何内容可以防止node为空,因为通常 IEnumerable 对象(例如列表或集合)可以包含空作为有效项。

如果为 null 则不会引发错误previous(除非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();
    }
}
于 2012-12-18T19:10:25.260 回答
4

因此,我发布了另一个答案以回应您的评论:

“我已经检查过 node 是否为空,在任何时候都不是。”

如果这是真的,这里还有其他一些选择;

  1. 看一下node.previous类/结构定义。它可以实现一个 CUSTOM==运算符,与 null 相比会引发错误。例如,考虑Nullable<T>类型。它有一个重载的==运算符,如果 HasValue 属性为 false,则返回 true (显然,由于它是一个结构,它不是真正的 null,但重载运算符会给出所需的行为。)要解决这个问题,您可以测试object.ReferenceEquals(node.previous, null)哪个不会被超载。如果您有权更改node.previous定义,也许您可​​以找出为什么重载运算符与 null 相比会引发异常(显然不应该)

  2. nodes可能为 null,在这种情况下,引发错误的是 foreach 语句。nodes == null在 foreach 之前进行测试。

- - - - - - - -编辑 - - - - - - - -

正如Jeppe指出的那样,我与Nullable<T>(在上面的选项 #1 中)的类比可能会产生误导(实际上它确实混淆了讨论,尽管这一点本身是正确的)。为了更好地说明重写==运算符的想法,我在下面发布了一个示例来演示该Container类型。这种类型是一个结构,所以它本身永远不能为空,但它包含一个值对象。(这个结构的要点是你可以使用任何Container对象而不用担心它是否为空,即使包含的Value对象可能是空的)。主要需要注意的是,当将 Container 与==null 进行比较时,如果Valueis则结果将为 true 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

以防万一您想知道覆盖==将如何影响一个类,我在下面编写了另一个示例来演示一个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 ==)
于 2012-12-18T19:16:58.637 回答
1

如果nodesnull异常将在循环之前发生,并且不会捕获异常。

由于previous成员是一个简单的字段,我看到的唯一可能是您的集合中的一个node成员是. 你可以这样做:nodesnull

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);
}

但是您必须==修复重载的错误实现。

如果您在原始问题中发布了异常的堆栈跟踪,那么 SO 上的大多数用户都会清楚异常来自对您的==重载的调用。所以下一次,检查你的堆栈跟踪。

于 2012-12-18T19:15:00.810 回答
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();}
        }
}
于 2012-12-18T19:12:52.807 回答
0

没有什么可以确保它node不为空,因为Node它不是值类型。介意提供更多细节吗?

于 2012-12-18T19:04:41.940 回答
0

在您的行中设置一个断点,bool并验证该节点不为空且节点不为空。我的猜测是任何一个节点都是空的,或者如果它不是类型安全的列表,它包含一个空值。

于 2012-12-18T19:05:22.167 回答