C# record ToString() 导致堆栈溢出并停止调试会话并出现奇怪的错误
C# record ToString() causes stack overflow and stops debugging session with a strange error
我写了一个单元测试,并使用新的 C# 记录来存储一些测试所需的数据。单元测试 运行 很好,但是当我设置断点并将鼠标移到记录变量名称上时,调试会话结束并且我收到一条看起来很奇怪的错误消息。
为了向 Microsoft 报告该问题,我编写了一个简单的单元测试来演示该问题,但除此之外没有多大意义:
#nullable enable
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace CSharpRecordTest {
record Twin(string Name) {
public Twin? OtherTwin { get; set; }
}
[TestClass]
public class UnitTest1 {
[TestMethod]
public void TestMethod1() {
var twinA = new Twin("A");
var twinB = new Twin("B");
twinA.OtherTwin = twinB;
twinB.OtherTwin = twinA;
Assert.AreEqual(twinA, twinA.OtherTwin.OtherTwin);
}
}
}
测试 运行 没问题,但是当在 Assert.AreEqual( 处设置断点并将鼠标移到 twinA 上时,调试会话停止并显示此错误消息:
我花了一两天时间才弄清楚发生了什么,因为调试器没有让我看到任何东西。我写了一个控制台应用程序:
class Program {
record Twin(string Name) {
public Twin? OtherTwin { get; set; }
}
static void Main(string[] args) {
var twinA = new Twin("A");
var twinB = new Twin("B");
twinA.OtherTwin = twinB;
twinB.OtherTwin = twinA;
Console.WriteLine(twinA);
}
}
控制台应用程序也 运行 遇到了麻烦,但至少它表明有一个堆栈超过 运行 并且它导致了哪一行:
Console.WriteLine(twinA);
堆栈看起来像这样(虽然更复杂):
twinA.OtherTwin.OtherTwin.OtherTwin.OtherTwin.OtherTwin.OtherTwin...OtherTwin.ToString()
问题是编译器自动编写的 ToString() 在每个 属性.
上再次调用 .ToString()
如果一条记录引用自身或其他引用第一条记录的记录,ToString() 将失败并且需要与 Equals()、GetHashCode() 以及更多(我没试过)一起被覆盖.
实际上,当有一个非只读的 属性 时,Equals() 和 GetHashCode() 应该被覆盖,否则像 Dictionary 这样的 类 将不起作用。
有关详细信息,请参阅我在 CodeProject 上的文章:C# 9 Record: Compiler Created ToString() Code can Lead to Stack Overflow and Worse
我写了一个单元测试,并使用新的 C# 记录来存储一些测试所需的数据。单元测试 运行 很好,但是当我设置断点并将鼠标移到记录变量名称上时,调试会话结束并且我收到一条看起来很奇怪的错误消息。
为了向 Microsoft 报告该问题,我编写了一个简单的单元测试来演示该问题,但除此之外没有多大意义:
#nullable enable
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace CSharpRecordTest {
record Twin(string Name) {
public Twin? OtherTwin { get; set; }
}
[TestClass]
public class UnitTest1 {
[TestMethod]
public void TestMethod1() {
var twinA = new Twin("A");
var twinB = new Twin("B");
twinA.OtherTwin = twinB;
twinB.OtherTwin = twinA;
Assert.AreEqual(twinA, twinA.OtherTwin.OtherTwin);
}
}
}
测试 运行 没问题,但是当在 Assert.AreEqual( 处设置断点并将鼠标移到 twinA 上时,调试会话停止并显示此错误消息:
我花了一两天时间才弄清楚发生了什么,因为调试器没有让我看到任何东西。我写了一个控制台应用程序:
class Program {
record Twin(string Name) {
public Twin? OtherTwin { get; set; }
}
static void Main(string[] args) {
var twinA = new Twin("A");
var twinB = new Twin("B");
twinA.OtherTwin = twinB;
twinB.OtherTwin = twinA;
Console.WriteLine(twinA);
}
}
控制台应用程序也 运行 遇到了麻烦,但至少它表明有一个堆栈超过 运行 并且它导致了哪一行:
Console.WriteLine(twinA);
堆栈看起来像这样(虽然更复杂):
twinA.OtherTwin.OtherTwin.OtherTwin.OtherTwin.OtherTwin.OtherTwin...OtherTwin.ToString()
问题是编译器自动编写的 ToString() 在每个 属性.
上再次调用 .ToString()如果一条记录引用自身或其他引用第一条记录的记录,ToString() 将失败并且需要与 Equals()、GetHashCode() 以及更多(我没试过)一起被覆盖.
实际上,当有一个非只读的 属性 时,Equals() 和 GetHashCode() 应该被覆盖,否则像 Dictionary 这样的 类 将不起作用。
有关详细信息,请参阅我在 CodeProject 上的文章:C# 9 Record: Compiler Created ToString() Code can Lead to Stack Overflow and Worse