【问题标题】:When stepping through my program the ToString() method is being called for no reason单步执行我的程序时,无缘无故地调用了 ToString() 方法
【发布时间】:2014-01-07 19:51:34
【问题描述】:

这是一个奇怪的问题,我让我旁边的高级程序员也感到困惑。完整的问题是我的 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。

【问题讨论】:

    标签: c# visual-studio-2010 debugging tostring


    【解决方案1】:

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

    拥有一个您通常希望避免使用的非常“昂贵”的ToString 是一种需要警惕的情况。偶尔会有一些例外,但调用者通常希望它是一个便宜的操作。考虑是否适合使用一些其他方法/属性来表示涉及更多的显示字符串,留下更简单/更便宜的ToString 实现。

    【讨论】:

    • 听起来类似于覆盖控件的 OnPaint 事件并在设计视图中引发错误时发生的情况。
    • 你也可以在你的类中添加一个DebuggerDisplayAttribute,当附加调试器时将使用它来代替ToString:msdn.microsoft.com/en-us/library/ms228992(v=vs.110).aspx
    • @Logarr Meh,调试器可以很好地处理这里的异常;它只是说有一个异常而不是使调试器崩溃。
    【解决方案2】:

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

    如果你看属性,get方法有副作用,也会出现类似的问题。

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

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

    【讨论】:

      【解决方案3】:

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

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

      MSDN Ref

      【讨论】:

        【解决方案4】:

        正如其他人所提到的,调试器将调用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
            }
        

        【讨论】:

          【解决方案5】:

          把 ToString() 函数的名字改成别的什么

          【讨论】:

          • 这将改变程序在调试器之外的行为。他很可能在整个程序中都依赖ToString 的这种实现。
          • @Servy:我无法理解!你能解释一下你的意思吗?
          • 他可能在某处有Console.WriteLine(form),或者使用接受object 类型对象的日志框架,然后依赖使用ToString 来获取对象的字符串表示。这会破坏任何此类代码,但不会产生编译器错误。
          • 哦!我没有注意到“覆盖”这个词。对不起!
          猜你喜欢
          • 2015-02-21
          • 2016-09-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多