C# 修改string.Substring

C# 修改string.Substring,c#,string,substring,extension-methods,C#,String,Substring,Extension Methods,10次中有9次,当我想对字符串使用Substring()方法时,这是因为我想从字符串的末尾而不是开头刮去一些字符。虽然默认子字符串确实支持这一点,但它通过采用第二个参数来实现,该参数是所需字符串的长度,而不是端点。这意味着,如果我一直想从一系列长度不同的字符串中去掉N个字符,我必须多做一步,这会产生更多的代码。例如: //Shaving the first N chars string trimmed = foo.bar.widget.GetType().Name.Substring(N);

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

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

或者,为了保存额外的函数调用,请使用第二行:

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#文档,答案是“不”

可以说,这是一件好事™, 因为否则,你的代码将变成一场噩梦,让不熟悉你的扩展的人阅读


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

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

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"

就我个人而言,我觉得这比子字符串(-1)或仅仅是子字符串(varName)更具可读性,其中varName恰好是负数。

解决问题的好办法!这就是我喜欢的。将其称为
LeaveOff
,作为对
Take
补充的
IEnumerable
扩展方法的特化。重新调整
子字符串的用途
令人困惑,尽管(甚至是因为)巧妙地使用了命名参数。嗯,它确实有效,但无论何时使用它,都会令人烦恼地混淆Intellisense(自动将参数更改为无意义的“`DataGridViewTriState”)。因此,虽然它确实起到了一定的作用,但我认为我最好还是为扩展方法使用一个不同的名称。尽管如此,聪明的解决方案还是+1。我可能会找到其他地方我可以使用这个技巧。只是注意到那里有一个错误<代码>“abc”。对于
删除()
,子字符串(1)将返回
“bc”
,而不是
“a”
+1。它只从我的版本中保存了几个字符,但很高兴知道有一个为此目的而构建的函数。我仍然认为我将使用扩展方法,因为这仍然要求我要么获取字符串两次,要么将其保存在局部变量中,就像我最初的示例一样。无论如何,文档链接基本上给了我答案。遗憾的是,最初的设计不是为了这样工作,因为提供这两种方法似乎是一种非常简洁的方式。@DarrelHoffman不允许使用负字符串位置,因此需要使用不同的方法名称来表示意图,这样做的优点是增加了发现由位置计算错误引起的编程错误的可能性。缺点是非常有限的:字符串算法很少需要在同一表达式中指定起始或结束位置。@TomBlodget您确实看到一些字符串格式表达式是这样工作的。与旧的C-style
printf
一样,函数用于将文本与前导或尾随空格对齐,使用负值表示右对齐,使用正值表示左对齐。一开始可能会让人困惑,但这是一种非常常见的形式,并非没有先例。
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"