6

更新:我已经解决了我遇到的问题,但我不知道为什么该错误会生成它所做的堆栈跟踪。堆栈跟踪将我引向完全错误的方向。如果有人能解释这里发生了什么,我将不胜感激(并将您的答案标记为已接受)。请注意,我的原始帖子已被删除。

我有以下课程。它的不相关部分已被删除:

class ClassName {
    private string[] _accountTypes = new string[2] {"ECOM", "MOTO"};

    private Dictionary<string, string> _settleDueDateDictionary = new Dictionary<string, string>() {
        {"0", "Process immediately."},
        {"1", "Wait 1 day"},
        {"2", "Wait 2 days"},
        {"3", "Wait 3 days"},
        {"4", "Wait 4 days"},
        {"5", "Wait 5 days"},
        {"6", "Wait 6 days"},
        {"7", "Wait 7 days"},
    };


    private string _settleDueDate;

    private string _accountTypeDescription;


    public string SettleDueDate
    {
        get
        {
            DateTime today = DateTime.Today;
            long settleDueDate = Convert.ToInt64(_settleDueDate);
            return today.AddDays(settleDueDate).ToString("MM/dd/yyyy");
        }
        set
        {   
            if (!_settleDueDateDictionary.ContainsKey(value)) {
                // TODO - handle
            }
            _settleDueDate = value;
        }
    }

    public string AccountTypeDescription
    {
        get {
            //return AccountTypeDescription; // This would cause infinite recursion (not referring to backing property).
            return _accountTypeDescription; // This fixed the StackOverflowException I was faxed with
        }
        set
        {
            if (!_accountTypes.Contains(value))
            {
                // TODO - handle
            }
            _accountTypeDescription = value;
        }
    }
}

我也有这个类,它采用上面类的一个实例,并使用实例中的值创建了一个 XML 字符串:

class SecondClass
{
    private ClassName classnameInstance;

    public SecondClass(ClassName instance)
    {
        classnameInstance = instance;
    }

    public string PrepareRequest(XMLWriter writer)
    {
        writer.WriteElementString("accounttypedescription", classnameInstance.AccountTypeDescription);
    }
}

这是生成堆栈跟踪的客户端代码:

STPPData STPP = new STPPData();

STPP.SiteReference = _secureTradingWebServicesPaymentSettings.SiteReference;
STPP.Alias = _secureTradingWebServicesPaymentSettings.Alias;

STPP.SettleDueDate = Convert.ToString(_secureTradingWebServicesPaymentSettings.SettleDueDate);
STPP.SettleStatus = _secureTradingWebServicesPaymentSettings.SettleStatus;
STPPXml STPPXml = new STPPXml(STPP);

XmlWriterSettings settings = new XmlWriterSettings();
settings.Async = false;
var builder = new StringBuilder();

using (XmlWriter writer = XmlWriter.Create(builder, settings))
{
    string xmlRequest = STPPXml.PrepareRequest(writer);
}

最后,这是堆栈跟踪:

mscorlib.dll!string.GetHashCode()
mscorlib.dll!System.Collections.Generic.GenericEqualityComparer<System.__Canon>.GetHashCode(SYstem.__Canon obj)
mscorlib.dll!System.Collections.Generic.Dictionary<string,string>.FindEntry(string key)
mscorlib.dll!System.Collections.Generic.Dictionary<System.__Canon,System.__Canon>.ContainsKey(System.__Canon key)
ClassName.SettleDueDate.set(string value)
ClassName.SettleDueDate.set(string value)
ClassName.SettleDueDate.set(string value)
// Infinite recursion of this call

这个堆栈跟踪让我相信我错误地为 STPP.SettleDueDate 实现了 getter/setter。我检查了它们并且支持变量等是正确的(我理解 getter/setter 中循环的常见原因)。进一步调试表明,调用此行时实际上生成了堆栈跟踪PrepareRequest()

writer.WriteElementString("accounttypedescription", STPPData.AccountTypeDescription);

我发现我错误地实现了 STPPData.AccountTypeDescription 的 getter,因为我创建了一个在 setter 中使用的支持属性,但我没有在 getter 中使用支持属性:

public string AccountTypeDescription
{
    get {
        //return AccountTypeDescription; // This would cause infinite recursion.
        return _accountTypeDescription; // This fixed the StackOverflowException
    }
    // setter omitted for clarity (it is in the examples above)
}

我的问题是:

当错误实际上在 AccountTypeDescription.get() 中时,为什么 StackOverflowException 的堆栈跟踪将我指向 SettleDueDate.set()?

注意:我是 C# 新手,来自 LAMP 背景。我已经稍微简化了代码,但我认为我没有删除任何重要的东西。

4

2 回答 2

1

以下是一些可以缩小问题范围的简单调试步骤

  • 使用 SettleDueDate 属性打开类
  • 右键单击 SettleDueDate 的属性名称
  • 单击菜单项“查找所有参考文献”
  • SettleDueDate 设置的每个地方,即 'SettleDueDate = "Something or other"' 添加断点
  • 运行应用程序并在断点被命中时继续运行,直到连续多次命中一个断点
  • 当您找到违规点并且代码位于断点上而不是继续使用 Step Out 命令和 Step over 命令来跟踪您的方式备份堆栈以找出递归分配的位置时
于 2012-12-07T18:49:10.733 回答
1

这段代码非常零碎,我不确定我是否完全理解所有的联系。我假设 ClassName == STPPData 和 SecondClass == STPPXml?尽管如此,我尝试使用 VS2010 和 .NET 4 重现此错误。我无法做到 - 堆栈跟踪仅在 AccountTypeDescription.set() 中显示无限递归。一定有什么东西不见了。

首先,堆栈跟踪中的这些行非常有趣:

mscorlib.dll!string.GetHashCode()
mscorlib.dll!System.Collections.Generic.GenericEqualityComparer<System.__Canon>.GetHashCode(SYstem.__Canon obj)
mscorlib.dll!System.Collections.Generic.Dictionary<string,string>.FindEntry(string key)
mscorlib.dll!System.Collections.Generic.Dictionary<System.__Canon,System.__Canon>.ContainsKey(System.__Canon key)

它们似乎明确显示了 SettleDueDate.set() 的内部结构,而不仅仅是对它的无限调用。存在字典和哈希查找。你肯定有一个错误在那里的某个地方。但是我有一种预感,您的源代码不包含错误。参考@Bryan 的回答,您是否在 SettleDueDate 设置器中设置了断点而不是在代码中调用它的位置?如果您使用的是 Visual Studio,您还可以使用此功能打破异常。

我看到您正在使用 Web 服务做一些事情,这立即让我想到了代理类。它们看起来很像您编写的代码,但它不是您编写的代码。他们可能会过时。你有多确定这个异常是由你编写和编译的代码引发的?

其次,Web 服务也让我想到了序列化,这个过程通常会在您不知情的情况下调用属性 getter 和 setter。过去,我在 WCF 尝试序列化 IEnumerables 时遇到过问题,并且即使我的代码很好,也失败了。

顺便说一句,在我的系统上,这条线没有编译:

if (!_accountTypes.Contains(value))

这让我想知道您使用的是 Mono 还是与我不同的 IDE。毕竟你是个灯人=)

我知道这不是一个真正的答案(还),但我想知道你对此有何看法?你还有什么可以分享的细节吗?

于 2013-03-08T20:39:25.893 回答