当单步执行我的程序时,无缘无故地调用ToString()方法

这是一个奇怪的问题,即使我旁边的高级程序员也很困惑。 完全问题是我的ToString()方法被调用,我不知道或不知道这是我的代码

 static void Main(string[] args) { Console.Out.WriteLine("Blank Constructor"); Form form = new Form(); <-- ToString() gets called on this line. form.ToString(); Console.Read(); } public Form() { FormName = ""; FormImageLocation = ""; FormDescription = ""; FormID = 0; CreatedDate = DateTime.Now; LastUpdate = DateTime.Now; Fields = new List(); Packets = new List(); <-- This line in the constructor } public override string ToString() { string returnString; returnString = " Form Name: " + FormName + " Form Image Location: " + FormImageLocation + "Form Description: " + FormDescription + " FormID: " + FormID + " Created Date: " + CreatedDate + " LastUpdate: " + LastUpdate ; if (fields.Count != 0) { foreach (var field in fields) { returnString += field.ToString(); } } else { returnString += "!!! This Form has no Fields !!!"; } if (Packets.Count != 0) { foreach (var packet in Packets) { returnString += packet.ToString(); } } else { returnString += " !!! This Form does not belong to any Packets !!!"; } Console.Out.WriteLine(returnString); return returnString; } public Packet(string packet_name, List
list_of_forms) { PacketName = packet_name; forms = list_of_forms; }

ToString()打印看似随机的重复发生仅在我单步执行程序时发生。 它会在我上面指定的行上打印,也会在构造函数退出并打印时像疯了一样,因为我正在逐步执行ToString()方法本身。 我在ToString()放置了一个断点,但是当合法地调用ToString()时它只会在断点处停止,因此当我单步执行并且它执行此随机打印时它将不会停止在断点内。 ToString() 。 我经历并删除了对ToString()所有调用,它仍然被随机调用,当我注释掉returnString变量并刚刚返回“她那里”时,问题就消失了,但这没有任何帮助。 如果我只运行没有断点的程序,则不会发生此问题。 你们中的一些人可能会说,如果它在运行时起作用并不重要但是它让我非常小心,如果我遇到代码问题,我试着通过代码来找到问题我会得到不同的结果并阻碍调试。 我尝试覆盖整个问题以及我尝试过并提供所需的所有代码,如果我不清楚某些事情让我知道,我会再次尝试解释它。 最后我在Windows 7 64位机器上,我使用的是Visual Studio C#2010 Express。

您可能在表单上有一个监视,或者以其他方式在调试器中显示它的值(通过“本地”窗口,堆栈跟踪等)。 调试器使用ToString来显示对象。 如果这是程序中的问题,您应该重新设计ToString ,这样就不会像这样调用它,或者只是避免使用调试器。

拥有一个非常“昂贵”的ToString ,你通常希望避免使用它是一个需要警惕的情况。 可能会偶尔出现例外情况,但是通话者通常认为它是一种廉价的操作。 考虑是否适合使用其他方法/属性来表示更复杂的显示字符串,从而留下更简单/更便宜的ToString实现。

如果你观看它,或者你只是将鼠标hover在对象上,调试器可能会调用ToString。 通常最好将ToString中的副作用保持在最低限度。 即ToString不应导致任何状态改变。

如果您观察属性并且get方法有副作用,则会出现类似的问题。

另一个问题是使用LINQ时,因为调试器可能会评估从LINQ表达式返回的IEnumerable,这可能会导致所有类型的副作用。 使用LINQ可能会变得更加棘手。 如果你有一些代码实际上依赖于重新评估LINQ表达式(比如一些代码轮询一些LINQ表达式直到某些条件为真),那么你可以在调试时获得一些白发,因为调试器可能会缓存表达式而不是 – 按预期评估它。

另一个类似的调试噩梦:调试焦点事件。 很难做到,因为激活调试器会窃取焦点并导致副作用。 有时好的旧式印刷陈述是最好的选择。

我认为,为了在Form()中显示那些DateTimes,当你尝试实例化一个新的Form()时,调试器正在调用它们的ToString()…正如@Servy提到的那样

由于您在Form()类中使用的不仅仅是字符串,因此必须调用ToString()以在您为调试设置的停止点中显示本地,并且您需要相应地使用DebuggerDisplayAttribute或更改方式你重写了ToString()。

MSDN参考

正如其他人所提到的,调试器将调用ToString以在多个位置可视化您的类。 这包括Autos,Locals和Watch窗口。 如果您不希望调试器调用ToString,或者想在连接调试器时发生短路,则可以选择几个选项。

DebuggerDisplayAttributeDebuggerTypeProxyAttribute

您可以将这两个属性之一添加到类定义中。 在调试器中运行时,它将获取这些属性并使用这些属性提供的替代方法或格式字符串,而不是ToString()方法。 以下显示表单Title属性。

 [DebuggerDisplay("MyForm under debugger {Title}")] public class MyForm : Form { } 

Debugger.IsAttached

您还可以在ToString方法的开头检查Debugger.IsAttached属性并实现替代行为。

  public override string ToString() { #IF (DEBUG) if ( Debugger.IsAttached ) { return this.GetType().Name + ": " + this.Title; // or something else. } #ENDIF // The rest of your ToString implementation } 

将ToString()函数的名称更改为sth else