【问题标题】:How is it possible in this code: "ArgumentOutOfRangeException: startIndex cannot be larger than length of string"?这段代码怎么可能:“ArgumentOutOfRangeException:startIndex 不能大于字符串的长度”?
【发布时间】:2013-07-20 01:59:23
【问题描述】:

我的 C# 代码中有以下方法:

/// <summary>
/// Removes the first (leftmost) occurence of a <paramref name="substring"/> from a <paramref name="string"/>.
/// </summary>
/// <param name="string">The string to remove the <paramref name="substring"/> from. Cannot be <c>null</c>.</param>
/// <param name="substring">The substring to look for and remove from the <paramref name="string"/>. Cannot be <c>null</c>.</param>
/// <returns>
/// The rest of the <paramref name="string"/>, after the first (leftmost) occurence of the <paramref name="substring"/> in it (if any) has been removed.
/// </returns>
/// <remarks>
/// <list type="bullet">
/// <item>If the <paramref name="substring"/> does not occur within the <paramref name="string"/>, the <paramref name="string"/> is returned intact.</item>
/// <item>If the <paramref name="substring"/> has exactly one occurence within the <paramref name="string"/>, that occurence is removed, and the rest of the <paramref name="string"/> is returned.</item>
/// <item>If the <paramref name="substring"/> has several occurences within the <paramref name="substring"/>, the first (leftmost) occurence is removed, and the rest of the <paramref name="string"/> is returned.</item>
/// </list>
/// </remarks>
/// <exception cref="ArgumentNullException">
/// The <paramref name="string"/> is <c>null</c>. -or- The <paramref name="substring"/> is <c>null</c>.
/// </exception>
public static string RemoveSubstring(string @string, string substring)
{
    if (@string == null)
        throw new ArgumentNullException("string");

    if (substring == null)
        throw new ArgumentNullException("substring");

    var index = @string.IndexOf(substring);
    return index == -1
        ? @string
        : @string.Substring(0, index) + @string.Substring(index + substring.Length);
}

实现看起来非常简单明了,并且通过单元测试具有出色的覆盖率。在我的机器、构建服务器或我有权访问的任何其他机器上,或者在大多数生产环境中,都没有出现意外结果。

除了只有一个远程客户偶尔会通过以下堆栈跟踪报告此方法的应用程序崩溃:

System.ArgumentOutOfRangeException: startIndex cannot be larger than length of string.  
Parameter name: startIndex   
   at System.String.InternalSubStringWithChecks(Int32 startIndex, Int32 length, Boolean fAlwaysCopy)  
   at System.String.Substring(Int32 startIndex)
   at MyNamespace.StringUtils.RemoveSubstring(String string, String substring)
   at ...

很遗憾,我无法远程访问此生产环境或其数据或任何其他信息。由于某些原因,目前我无法在那里部署日志记录系统或故障转储收集。

查看代码并尝试不同的参数组合,我无法想象这个异常是如何发生的。

你能帮我一些想法吗?

【问题讨论】:

  • IndexOf 是特定于文化的。查看示例here 以了解索引如何更改。
  • 您最好使用 String.Remove(Int32,Int32) 方法。你可能会发现它更宽容。 : @string.Remove(index, substring.Length)

标签: c# .net debugging exception substring


【解决方案1】:
RemoveSubstring("A", "A\uFFFD"); // throws ArgumentOutOfRangeException
RemoveSubstring("A", "A\u0640"); // throws ArgumentOutOfRangeException

.NET 中的许多字符串操作函数,包括 IndexOf,默认情况下都是特定于区域性的(通常有重载,您可以传递 StringComparison.OrdinalStringComparer.Ordinal 以切换到按位比较)。就我个人而言,我对选择的默认行为不是很满意,但现在做任何事情都为时已晚,除非设置明确的开发指南和 FxCop 规则。

但有时,特定于文化的操作正是您所需要的。不幸的是,它们的语义可能很棘手且违反直觉,可能违反一些通常假设的不变量,并且有很多极端情况需要处理。负责在应用程序中实现文化敏感逻辑的开发人员应该在这方面非常合格,并且始终准确地了解他们在做什么。我建议将此领域的审查和测试标准设置为高于正常水平。

【讨论】:

  • 您可以补充说,他可以通过将StringComparison.Ordinal 添加到IndexOf 来修复它。
  • 来自文档:msdn.microsoft.com/en-us/library/k8b1470s.aspx 字符集包括可忽略的字符,这些字符是在执行语言或文化敏感比较时不考虑的字符。在区分区域性的搜索中,如果 value 包含可忽略的字符,则结果等同于删除该字符进行搜索。 ...
【解决方案2】:

在 cmets 之后,我发现子字符串不会在无效索引上失败。真正的问题在于

@string.IndexOf(substring);

正如 Pierre-Luc Pineault 所指出的

更正:

@string.IndexOf(substring, StringComparison.Ordinal);

【讨论】:

  • ABCDEF 和 EF 正确返回 ABCD。您是否尝试运行代码?
  • 你是对的。我刚刚测试了代码,发现子字符串在这种情况下是宽容的。
猜你喜欢
  • 2019-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多