【问题标题】:Modifying string.Substring修改 string.Substring
【发布时间】:2014-01-02 09:45:35
【问题描述】:

10 次中有 9 次,当我想对字符串使用 Substring() 方法时,这是因为我想从字符串的 END 而不是开始处刮掉一些字符。虽然默认的 Substring 确实支持这一点,但它通过采用第二个参数来实现,该参数是所需字符串的长度,而不是端点。这意味着如果我一直想从一系列不同长度的字符串中删除 N 个字符,我必须做一个额外的步骤,这可能会产生更多的代码。举个例子:

//Shaving the first N chars
string trimmed = foo.bar.widget.GetType().Name.Substring(N);

对比

//Shaving the last N chars
string trimmed = foo.bar.widget.GetType().Name.Substring(0, foo.bar.widget.GetType().Name.Length - N);

或者为了节省额外的函数调用,使用第二行:

string name = foo.bar.widget.GetType().Name;
string trimmed = name.Substring(0, name.Length - N);

无论哪种方式,您基本上都将需要从字符串末尾而不是开头删除字符的代码量增加了一倍。我的修改会很简单。如果你传递一个负数 N(否则这将毫无意义),它会将 -N 字符从字符串的末尾而不是开头剃掉。我已经可以使用扩展方法对其进行编码了:

public static string MySubstring(this string str, int val)
{
    return (val > 0) ? str.Substring(val) : str.Substring(0, str.Length + val);
}

然后当我想剃掉最后的 N 个字符时,我就这样做了:

string trimmed = foo.bar.widget.GetType().Name.MySubstring(-N);

短而甜,就像剃掉开头的字符一样。我的问题是 - 是否可以覆盖默认 Substring() 函数的行为,以便我可以做到这一点而不必为函数使用我自己的唯一名称?它不会使任何现有代码无效,因为以前没有理由将负数传递给它,这样做只会引发异常并崩溃。这只是那些简单的、严肃的功能之一,感觉它应该从一开始就成为实现的一部分。

【问题讨论】:

    标签: c# string substring extension-methods


    【解决方案1】:

    根据 C# 文档,you can use extension methods to extend a class or interface, but not to override them. An extension method with the same name and signature as an interface or class method will never be called. 所以答案是“否”。

    可以说,这是一件好事™,否则您的代码将成为不熟悉您的扩展程序的人阅读的噩梦。

    注意:str.Substring(0, str.Length + val);可以替换为str.Remove(str.Length + val)

    【讨论】:

    • +1 表示Remove()。它只保存了我的版本中的几个字符,但很高兴知道有一个为此目的而构建的函数。仍然认为我会使用扩展方法,因为这仍然需要我两次获取字符串,或者将其保存在局部变量中,就像我原来的例子一样。无论如何,文档链接基本上给了我我的答案。遗憾的是,原始版本一开始就没有以这种方式工作,因为它似乎是提供两种方法的一种很好的简洁方式。
    • @DarrelHoffman 不允许负字符串位置,因此需要使用不同的方法名称来表示意图,这样做的好处是增加了发现因位置计算错误导致的编程错误的可能性。缺点非常有限:字符串算法很少需要从相同表达式的开头或结尾指定位置。
    • @TomBlodget 但是,您确实看到了一些以这种方式工作的字符串格式化表达式。就像旧的 C 风格 printf 函数用于将文本与前导或尾随空格对齐,使用负值表示右对齐,使用正值表示左对齐。一开始可能会让人感到困惑,但这是一种足够常见的形式,并非没有先例。
    【解决方案2】:

    您不能使用扩展方法在严格意义上覆盖字符串上的方法,因为编译器在编译方法调用时总是会选择实例方法而不是具有相同签名的扩展方法。但是,您可以使用命名参数实现接近您想要的效果。这也应该有助于避免可读性问题。这是一个例子

    public static string Substring(this string @this, int trimFromEnd)
    {
        return @this.Substring(0, @this.Length - trimFromEnd);
    }
    
    // if you do
    "abc".Substring(1) -> returns "bc"
    
    // if you do
    "abc".Substring(trimFromEnd: 1) -> returns "ab"
    

    就我个人而言,我发现这比 Substring(-1) 或只是 Substring(varName) 更具可读性,其中 varName 恰好是负数。

    【讨论】:

    • 解决问题的好方法!这就是我喜欢的。
    • 称它为LeaveOff 是对IEnumberable 扩展方法的一种专门化,它是Take 的补充。尽管(甚至是因为)巧妙地使用了命名参数,但重新利用 Substring 会让人感到困惑。
    • 嗯,它确实有效,但它会在你使用它时烦人地混淆 Intellisense,(自动将参数更改为无意义的“`DataGridViewTriState”)。因此,虽然它确实起到了作用,但我认为我最好为扩展方法使用不同的名称。不过,+1 是聪明的解决方法。我可能会找到其他可以使用该技巧的地方。
    • 刚刚注意到那里有一个错误..."abc".Substring(1) 将返回"bc",而不是"a"
    猜你喜欢
    • 2013-11-20
    • 2013-03-02
    • 2012-12-09
    • 2019-11-15
    • 2016-03-15
    • 2014-10-06
    • 2012-02-24
    • 1970-01-01
    • 2011-01-15
    相关资源
    最近更新 更多