决定LinkedList
使用IEnumerable
. 问题就在其中。我有一个方法Contains(..)
,在使用 foreach 时不会引发异常。有一个AddAfter(..)
抛出异常的方法。有两件事让我感到困惑:
在 while(currentNode!=null) 循环中发生异常(但在 currentNode==null 处发生崩溃)
即使异常设置说“中止”,程序也不会在没有调试的情况下在启动时崩溃
这些是功能:
public IEnumerator <T> GetEnumerator()
{
currentNode = firstNode;
while (currentNode != null)
{
yield return currentNode.Data;
currentNode = currentNode.Next;
}
}
public bool Contains(T item)
{
foreach (var t in this)
{
if (t.Equals(item))
return true;
}
return false;
}
public bool AddAfter(T item, T after)
{
if (this.Contains(item))
{
return false;
}
foreach (var t in this) // где-то здесь вылетает
{
if (t.Equals(after))
{
currentNode.Next = new Node <T>(item, currentNode, currentNode.Next);
if (currentNode == lastNode)
lastNode = lastNode.Next;
return true;
}
}
lastNode.Next = new Node <T>(item, lastNode, null);
lastNode = lastNode.Next;
return true;
}
调试器运行Contains()
没有问题,但没有foreach
显示问题。在非调试模式下,NullPointerException 不会停止程序(或根本不出现),它会悄悄地跨过去foreach
并出现不正确的数据。也许我不知何故理解不正确yield return
?我了解第一次输入该函数时,所有行都到yield return
. 使用第二个,将执行后面的行yield
,程序将沿着循环继续前进。然后发现currentNode在访问之间被重置了?
那不是全部。如果您开始调试,但同时不进入这个有问题的调试,foreach
那么,再一次,不会发生异常,程序只显示预期的结果。但是如果你在调试的时候进入这个foreach
,就会出现异常,如第二张截图所示。它是如何工作的?
我这样完成这个列表:
var tb = TextField; // textBox
var list = new MyGenListUnique <int>();
list.AddRange(new []{0,1,2,3,4,5,6,7});
tb.AppendText(list.ToString() + Environment.NewLine);
list.AddAfter(-12, 2); // {0,1,2, -12, 3,4,5,6,7} // проблема здесь
tb.AppendText(list.ToString() + Environment.NewLine);
以下是附加函数和相关函数:
public int AddRange(T[] items)
{
if (items is null)
{
return 0;
}
var countAdded = 0;
foreach (var t in items)
{
var currCount = Count;
Add(t);
if (currCount > Count)
countAdded++;
}
return countAdded;
}
public void Add(T item)
{
if (firstNode is null)
{
firstNode = new Node <T>(item, null, null);
lastNode = firstNode;
return ;
}
if (!this.Contains(item))
{
lastNode.Next = new Node <T>(item, lastNode, null);
lastNode = lastNode.Next;
IncreaseCount();
return ;
}
}
public new string ToString()
{
var sb = new StringBuilder(100);
sb.Append("{ ");
foreach (var t in this)
{
sb.Append(t + " ");
}
sb.Append("}");
return sb.ToString();
}
private void IncreaseCount(int count = 1)
{
Count += count;
}
Count
- autoproperty
,默认构造函数为空。如果是这样,这里是类Node<T>
private class Node <T>
{
public T Data;
public Node <T> Next { get; set; }
public Node <T> Prev { get; set; }
public Node() {}
public Node(T data, Node <T> prev, Node <T> next)
{
Data = data;
Next = next;
Prev = prev;
}
}
这里的一切都很简单。您的调用在每次调用中
GetEnumerator()
使用相同的变量currentNode
,这是一个错误,因为不同的枚举数必须是独立的。在没有调试器的情况下运行时,这不起作用,因为您不会
GetEnumerator
多次调用。但是当您在调试器下运行时,调试器本身会调用
GetEnumerator()
以显示变量的值this
。更准确地说,是演播室电话ToString()
,你已经打通了GetEnumerator()
——但电话GetEnumerator()
也可以想象。public
因此,道德:编写较少混淆的代码,并始终准备好让某人调用声明为方法的方法。具体来说,在您的代码中,要修复错误,您需要将其设为
currentNode
局部变量。并用这个替换循环foreach (var t in this)
:好吧,我在项目属性中关闭了优化。打开它 - 一切都很好,调试期间的行为对应于没有调试的行为。不幸的是,这可能很重要。