不直观的C#String.Split()实现的原因


10

在C#中,如果我想将a分开stringstring则必须执行以下操作:

testString.Split(new string[] { "anotherString" }, StringSplitOptions.None);

从过载的String.SplitMSDN文档中,我们可以看到实现以及为什么必须进行这样的调用。

来自Python,我很难正确理解为什么需要这样的调用。我的意思是我可以Regex.Split用来获得与Python实现类似的语法,但是对于任何简单的事情,我都必须以降低性能(设置时间)为代价来实现。

因此,基本上,我的问题是,为什么我们不能做这样的事情:

testString.Split("anotherString");

请注意,我不建议任何原型或实现。我了解,考虑到当前的API,为什么您无法实现上述版本。我的目标是考虑到上述语法带来的好处,为什么要创建这样的API。到目前为止,灵活性似乎已成为当前潮流的目标String.Split,但老实说,我确实认为在某种程度上可以提高性能。我想我错了。


3
我也在考虑这个。我的猜测是,他们只是没有花太多精力来设计这个API。如果他们意识到自己的错误,那就太迟了。
欣快的

@Caleth您能否详细说明这一点。也许我错了,但我看不出有什么歧义。我为什么不能做,testString.Split(",.;");testString.Split(new Char [] {',', '.', ';',);那又是不一样的。
scharette

@Euphoric我也很坚强,但这太奇怪了。希望有人能提供更多逻辑答案。
scharette

您可以像迭代字符串一样遍历字符串,IEnumerable<char>因此,您建议的其他原型在某些情况下可能会模棱两可(您是按整个字符串来界定还是按其每个字符来界定?)只是一个猜测。
John Wu

@JohnWu也许这是个人的事情,但是对于99.9%的诸如之类的语法testString.Split("anotherString");,我很自信地说预期的行为是对整个字符串进行定界(anotherString在这种情况下)。
scharette

Answers:


15

有时拆分多个字符/字符串很有用,因此API允许您提供一个数组,从而为您提供最大的灵活性。在chars 的情况下,由于参数标记为,params因此语法和灵活性都得到简化,因此您可以编写Split('x')而不是Split(new[]{'x'})

那么,为什么没有类似的字符串选项允许您编写Split("x")呢?

这可能是API设计方式的不幸结果。最初,它仅允许按字符分割。在2.0中添加了字符串拆分功能,这可能是因为实现起来更加复杂。但这是不可能添加String.Split(string)String.Split(string[])重载的,因为这将使表达式变得testString.Split(null)模棱两可,并且此代码将不再编译。

testString.Split(null) 实际上,这是一个非常常见的习惯用法,因为它在空格上分割了字符串,因此这种损坏太普遍了,无法接受。

null现在,通常将-parameter用作特殊行为的开关,这通常被认为是不好的设计,因此,我认为可以肯定地说此API有缺陷。

没有Split(string[], Int32)任何,可能由于类似的原因-它会含糊地Split(char[], Int32)如果第一个参数是null。这些参数也类似的重载StringSplitOptions,但是这些重载都是在2.0中同时添加的,因此在现有代码中没有引入歧义。

注意

需要明确的是,这只是我的假设,我不知道.net框架设计人员的实际想法。


1
好吧,那真的有用吗?怀疑。而且这只是一个API中断,而不是ABI中断。
Deduplicator

2
@Deduplicator:Split(null)在空白处进行拆分,因此即使使用这样的null是很糟糕的API设计,它也可能是拆分的最常见用例之一。
JacquesB

1
我认为@Deduplicator想要说的Split(null)是,如果您允许的话,那是没有用的Split("")。除了它可以提供更好的语法外,后者也更加冗长...
scharette

1
@scharette:可以,但是现在不能更改,而不会破坏向后兼容性。
JacquesB

1
注意:在当前的C#8预览中,通过关闭基本类型,可空性String.Split(null)将不再是模棱两可的,因此它们可以添加重载
BgrWorker

2

不是方法的作者,我不知道为什么选择了那套重载。但是,这里有两件事要注意:

  1. 如果您要分割一个字符,则public string[] Split(params char[] separator可以使用)版本:

    var splitValues = testString.Split(',');

    作为char[]一个params参数。

  2. 您可以在此处轻松添加自己的扩展方法以实现所需的功能:

    public static class StringExtensions
    {
        public static string[] Split(this string source, string separator)
            => source.Split(new string[] { separator }, StringSplitOptions.None);
    }

    现在testString.Split("anotherString");将为您工作。


1
感谢您的反馈。尽管您的回答是有益而简洁的,但我不同意您的看法。特别是第二点。内置它不是另一个理由吗?它所做的一切就是让社区创建每个人(或几乎每个人)都希望行为相同的方法的不同版本。
scharette

不用顺便辩论,您的观点是完全正确的。只是想了解其背后的原因。从逻辑上讲,必须有历史或性能原因……
scharette

@scharette:原因是使该方法尽可能通用。当您找到所选择的方法签名时,它最好不能用于多个定界符。Microsoft版本适用于多个定界符以及单个定界符。
罗伯特·哈维

@RobertHarvey好吧,两者都不可能吗?假设上述答案中的扩展方法是String类的一部分,两者都是可能的。我错了吗 ?
scharette

我认为您错过了重点。重载仅允许使用一个定界符。微软的超载不止一个。您不能多次调用过载并获得相同的结果。这不是这样的。
罗伯特·哈维

1

对于隐式转换和重载,不同的语言有一些不同的规则,.NET Framework旨在与它们中的任何一个一起使用。在Option Strict OffVB.NET 的方言中,String可以将type的值传递给期望a Char[]行为等同于调用ToCharArray()字符串的函数。

我认为明智的做法是为Split(接受一个CharString)和SplitMulti(接受一个Char[]String[])使用单独的名称,但是.NET有时似乎更喜欢单独使用重载来选择不同类型的操作。不幸的是,我不知道有什么方法可以String.Split用来适应任何需要区分不同类型的定界符的使用情况,除非在每个分隔符上分别进行拆分。

另一个遗漏是保留定界符的选项,定界符可以在前一个字符串的末尾或在后一个字符串的开始处包括它们,或者将奇数编号的数组元素作为分隔符,而偶数编号的元素作为分隔符。


1
.NET有时似乎更喜欢单独使用重载来选择不同类型的操作。如此真实……
scharette
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.