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

时间:2014-01-07 19:51:35

标签: c# visual-studio-2010 debugging 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<Field>();
    Packets = new List<Packet>(); <-- 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<Form> 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。

5 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:2)

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

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

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

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

答案 2 :(得分:1)

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

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

MSDN Ref

答案 3 :(得分:0)

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

DebuggerDisplayAttribute or DebuggerTypeProxyAttribute

您可以将这两个属性中的一个添加到类定义中。在调试器中运行时,它将获取这些属性并使用这些属性提供的替代方法或格式字符串,而不是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
    }

答案 4 :(得分:-4)

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