背景。 我的脚本在递归搜索大字符串中的特定文本时遇到 StackOverflowException。循环不是无限的;问题发生在 9,000-10,000 次合法搜索之间(对于特定搜索)——我需要它继续下去。我正在使用尾递归(我认为),这可能是我的问题的一部分,因为我认为 C# 做得不好。但是,我不确定如何避免在我的情况下使用尾递归。
问题)。为什么会发生 StackOverflowException?我的整体方法有意义吗?如果设计很糟糕,我宁愿从那里开始,而不仅仅是避免异常。但是如果设计是可以接受的,我能对 StackOverflowException 做些什么呢?
代码。 我编写的类在大量文本(约 6MB)中搜索联系人(来自指定列表的约 500 多个)。我使用的策略是搜索姓氏,然后在姓氏之前或之后不久的某处寻找名字。我需要在给定文本中找到每个联系人的每个实例。StringSearcher 类有一个递归方法,可以继续搜索联系人,只要找到一个就返回结果,但会跟踪搜索中断的位置。
我以下列方式使用这个类:
StringSearcher searcher = new StringSearcher(
File.ReadAllText(FilePath),
"lastname",
"firstname",
30
);
string searchResult = null;
while ((searchResult = searcher.NextInstance()) != null)
{
// do something with each searchResult
}
总的来说,该脚本似乎有效。大多数联系人返回我期望的结果。但是,当主要搜索字符串非常常见(数千次点击)而辅助搜索字符串从不或很少出现时,似乎会出现此问题。我知道它没有卡住,因为 CurrentIndex 正在正常推进。
这是我正在谈论的递归方法。
public string NextInstance()
{
// Advance this.CurrentIndex to the next location of the primary search string
this.SearchForNext();
// Look a little before and after the primary search string
this.CurrentContext = this.GetContextAtCurrentIndex();
// Primary search string found?
if (this.AnotherInstanceFound)
{
// If there is a valid secondary search string, is that found near the
// primary search string? If not, look for the next instance of the primary
// search string
if (!string.IsNullOrEmpty(this.SecondarySearchString) &&
!this.IsSecondaryFoundInContext())
{
return this.NextInstance();
}
//
else
{
return this.CurrentContext;
}
}
// No more instances of the primary search string
else
{
return null;
}
}
StackOverflowException 发生this.CurrentIndex = ...
在以下方法中:
private void SearchForNext()
{
// If we've already searched once,
// increment the current index before searching further.
if (0 != this.CurrentIndex)
{
this.CurrentIndex++;
this.NumberOfSearches++;
}
this.CurrentIndex = this.Source.IndexOf(
this.PrimarySearchString,
ValidIndex(this.CurrentIndex),
StringComparison.OrdinalIgnoreCase
);
this.AnotherInstanceFound = !(this.CurrentIndex >= 0) ? false : true;
}
如果需要,我可以包含更多代码。让我知道这些方法或变量之一是否有问题。
*性能并不是一个真正的问题,因为这可能会在晚上作为计划任务运行。