【问题标题】:What Does GetLineFromCharIndex() Really Do?GetLineFromCharIndex() 真正做什么?
【发布时间】:2009-01-22 23:04:12
【问题描述】:

我正在阅读 Ron Jeffries 的 C# 极限编程冒险。他的主要示例是一个简单的 XML 文本编辑器。考虑到这本书的年代(2004 年出版),我怀疑他的很多初始编码,找到光标在哪一行以及插入点在哪里,可以用新的 TextBox 方法或属性替换。我是Visual Studio 2005。为了保持敏捷开发和XP的精神,我先写了一些测试:

[Test]
public void TestGetFirstCharIndexOfCurrentLine() {
  String[] newlines = new string[] { "<P>one</P>", "<P>two</P>" }; //TextLength == 20
  notepad.txtbox.Lines = newlines;
  Expect(notepad.txtbox.SelectionStart, EqualTo(20));
  Expect(notepad.txtbox.GetFirstCharIndexOfCurrentLine(), EqualTo(11));
  Expect(notepad.txtbox.GetLineFromCharIndex(11), EqualTo(1));
}

(我很懒惰(呃……我的意思是我正在努力节省空间)。这段代码实际上结合了我在不同方法中实际运行的三个测试。)

无论如何,每个测试都会失败。首先,txtbox.SelectionStart 返回 0。这可能与文档建议的一致,但是当我在调试中逐步执行时,该值为 20。其他两个测试产生类似的结果;一个零,我期望一个正整数值。尤其是后两种情况,不符合我对文档的阅读。

我真的很感激我哪里出错了。

【问题讨论】:

    标签: c# unit-testing


    【解决方案1】:

    好的,我没有测试过这些,但我可以对你的每个结果的原因做出相当有根据的猜测:

    1. 正常执行时(不单步执行),您会期望 SelectionStart 保持为 0,因为需要通过 Windows 消息泵获取属性值,而该消息泵还没有时间运行。但是,在单步执行时,消息泵确实有时间执行,因此 SelectionStart 将引用文本的结尾。我对此没有信心,因此我建议进行一些测试。
    2. 现在应该很明显了,前提是第 1 点有效。
    3. 我相信位置 11 的字符实际上是一个 CR(ASCII 13),它可以被解释为第一行的一部分。诚然,这有点令人困惑。第二行的位置 12(或者肯定是 13)应该返回 1。

    这应该可以解释一些事情,但如果有任何进一步的测试不同意我的解释,请告诉我。

    【讨论】:

    • 好的,你对 CR 的看法是正确的。即使它没有出现在调试器中并且不影响文本长度,它也会被计算在内。还在研究另外两个。谢谢!
    【解决方案2】:

    我想我有一些答案。这似乎是诺多林所说的 message.pump 的扩展。

    如果我这样做:

      String[] newlines = new string[] { "<P>one</P>" }; //TextLength == 10
      notepad.txtbox.Lines = newlines;
      notepad.txtbox.AppendText("\n<P>two</P>");
      Expect(notepad.txtbox.SelectionStart, EqualTo(21));
    

    测试通过。 (顺便说一句,我首先使用此表单只是为了向自己证明 AppendText 方法有效。)但是,如果我这样做:

      String[] newlines = new string[] { "<P>one</P>","<P>two</P>" };
      notepad.txtbox.Lines = newlines;
      Expect(notepad.txtbox.SelectionStart, EqualTo(21));
    

    测试失败。

    除了第一种情况触发了一些重置 SelectionStart 属性的事件之外,我没有真正的解释。第二种情况只是用两行实例化文本框,不触发任何事件,并将 SelectionStart 保留为 0。

    有趣的是,下面的工作正好相反:

    [Test]
    public void TestGetLineFromCharIndex_UseAppendText() {
      String[] newlines = new string[] { "<P>one</P>" }; //TextLength == 10
      notepad.txtbox.Lines = newlines;
      notepad.txtbox.AppendText("\n<P>two</P>");
      Expect(notepad.txtbox.GetLineFromCharIndex(15), EqualTo(1));    
    }
    
    [Test]
    public void TestGetLineFromCharIndex() {
      String[] newlines = new string[] { "<P>one</P>", "<P>two</P>" };
      notepad.txtbox.Lines = newlines;
      Expect(notepad.txtbox.GetLineFromCharIndex(15), EqualTo(1));
    }
    

    第一次测试失败;第二次通过!生活不是很精彩吗? 我会再胡闹一点;我希望这对某人有帮助!

    【讨论】:

    • 顺便说一句,在第二次 SelectionStart 测试中,返回为 0,所以不仅仅是我数错了字符。
    【解决方案3】:

    不确定这是否能解决问题,但请在完成所有 TextBox 操作后尝试插入以下行(即在第一次 Expect 调用之前):

    Application.DoEvents();
    

    这应该允许 Windows 消息泵短暂运行,并确保 TextBox 处于正确状态,而不管其他一切。此外,您上一篇文章的第二个测试可能会失败,因为您在调用 AppendText 时使用了 \n 而不是 \r\n (标准换行符序列)。

    【讨论】:

    • \r\n!太多的Linux,我猜。这让测试通过,我假设是因为 MS 无法正确计算行数。不过,不知道为什么会这样。哦,好吧,生活,学习,继续前进!谢谢!
    • 是的,换行可能是一个令人困惑的问题。 Windows 上也存在/可接受单字符换行符(\r 和 \n),但仅在某些情况下(我不会假装理解)。这就是为什么在处理来自未知来源的文本时标准化换行符通常是明智的。
    • System.Environment.Newline 照顾它,我猜。我得检查一下 MONO 看看它是否有同样的东西。
    【解决方案4】:

    通过阅读测试,GetLineFromCharIndex 似乎应该返回与组合字符串中字符索引对应的行号。我怀疑我们在测试中遗漏了一些设置,因为 GetFirstCharIndexOfCurrentLine() 应该返回 0(我认为它是从零开始的)而不是 11,因为当前行应该从 0 开始。

    【讨论】:

    • 它肯定会返回零,但是该方法的意义何在?或者,“索引”在这种情况下的真正含义是什么?文档是否是 Text 属性的索引是模棱两可的,因此第一行中只有第一个字符是 0。更多关于下一块岩石...
    • 或者,每行是否有单独的索引。如果是后者,则该方法毫无价值,因为它总是返回零。我想这是真正的问题 - MS 没有定义 Index 在这种情况下的含义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-05
    相关资源
    最近更新 更多