直感的でないC#String.Split()実装の背後にある理由


11

C#ではstring、別のものstringを分割したい場合は、そのようなことをしなければなりません:

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

オーバーロードされたString.SplitMSDNドキュメントから、実装とそのような呼び出しを行う必要がある理由を確認できます。

Pythonから来たので、なぜこのような呼び出しが必要なのかを正しく理解するのは難しいです。Regex.SplitPythonの実装と同様の構文を取得するために使用できましたが、単純なものではパフォーマンス(セットアップ時間)が低下するという犠牲を払う必要があります。

だから基本的に、私の質問は、なぜ地獄ができないのかということです:

testString.Split("anotherString");

プロトタイプも実装も提案していないことに注意してください。現在のAPIを考慮して上記のバージョンを実装できない理由を理解しています。私の目標は、上記の構文がもたらす利点を考慮して、そのようなAPIが作成された理由を理解することでした。今のところ、柔軟性String.Split理にかなった現在の目標のようですが、正直なところ、どこかで何らかのパフォーマンスの向上があると本当に思っていました。私は間違っていたと思います。


3
私もこれについて考えていました。私の推測では、この1つのAPIの設計にはあまり努力していません。そして、彼らが自分の間違いに気づいたなら、手遅れでした。
陶酔

@Calethこれについて詳しく説明してください。多分私は間違っているが、私はそれについて曖昧なものが表示されません。なぜできないのかtestString.Split(",.;");testString.Split(new Char [] {',', '.', ';',);どれが同じではないのか。
-scharette

@Euphoric私もそう思いましたが、それはとても奇妙です。誰かがもっと論理的な答えを持ってくることを願っています。
-scharette

のように文字列を反復処理できるIEnumerable<char>ため、提案している追加のプロトタイプが特定の場合にあいまいに見える場合があります(文字列全体で区切るか、各文字で区切るか)。
ジョン・ウー

@JohnWu多分それは個人的なことかもしれませんが、のような構文の出現の99.9%についてtestString.Split("anotherString");、期待される動作は文字列全体(anotherStringこの場合)で区切ることであるとかなり確信しています。
-scharette

回答:


15

複数の文字/文字列で分割すると便利な場合があるため、APIを使用して配列を提供し、最大限の柔軟性を実現できます。以下の場合はcharS、あなたは、などのパラメータがマークされているので、構文と柔軟性の両方simplityを取得し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ブレークではありません。
デュプリケータ

2
@Deduplicator:Split(null)は空白で分割するため、このようなnullを使用するのは悪いAPI設計ですが、おそらく最も一般的な分割の使用例の1つです。
ジャックB

1
@Deduplicator Split(null)は、を許可すればそれは役に立たないと言いたかったと思いますSplit("")。より良い構文を可能にするという事実に加えて、後者はとにかくより冗長です
...-scharette

1
@scharette:もちろんです。しかし、後方互換性を損なうことなく、今すぐ変更することはできません。
ジャックB

1
注:現在のC#8プレビューでは、ベースタイプを無効String.Split(null)にすることで
nullability

2

メソッドの作成者ではないので、そのオーバーロードのセットが選択された理由はわかりません。ただし、ここで注意すべきことが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
フィードバックをお寄せいただきありがとうございます。あなたの答えは有用で簡潔ですが、私はあなたに同意できません。特に2番目のポイント。組み込みのもう1つの理由はありませんか?コミュニティがすべてのメソッド(またはほぼ全員)が同じように動作することを期待するメソッドの異なるバージョンを作成できるようにするだけです。
-scharette

ちなみに議論するつもりはありませんが、あなたの主張は完全に有効です。この背後にある理由を理解しようとしています。論理的には、歴史的またはパフォーマンス上の理由がなければなりません
...-scharette

@scharette:その理由は、メソッドをできるだけ汎用にすることです。選択したメソッドシグネチャを見つけるのが望ましいのですが、複数の区切り文字に対しては機能しません。Microsoftのバージョンは、単一の区切り文字だけでなく複数の区切り文字でも機能します。
ロバートハーベイ

@RobertHarveyまあ、両方とも不可能でしょうか?上記の答えの拡張メソッドがStringクラスの一部であったとしましょう。両方とも可能です。私が間違っている ?
-scharette

あなたはポイントを逃していると思います。オーバーロードで使用できる区切り文字は1つのみです。Microsoftのオーバーロードは複数を許可します。オーバーロードを複数回呼び出して同じ結果を達成することはできません。それはこれがどのように機能するかではありません。
ロバートハーベイ

1

言語によって、暗黙の変換およびオーバーロードのルールが多少異なり、.NET Frameworkはそれらのいずれでも使用できるように設計されています。Option Strict OffVB.NET の方言では、文字列の呼び出しと同等の動作Stringを期待する関数にtypeの値を渡すことができます。Char[]ToCharArray()

私が行うには賢明な事はに対して別々の名前持ってただろうと思いますSplit(単一受け入れるCharStringと)SplitMulti(受け入れることになるChar[]かをString[])が、.NETは時々操作の種類を選択するだけでオーバーロードを使用して好むようです。残念ながら、String.Splitそれぞれを個別に分割する以外に、さまざまな種類の区切り文字を区別する必要がある使用シナリオに対応する方法はありません。

もう1つの省略は、区切り文字を保持するオプションです。区切り文字は、前の文字列の末尾または次の文字列の先頭に含めるか、奇数番号の配列要素を区切り文字にし、偶数番号の要素を区切り文字にします。


1
.NETは、オーバーロードのみを使用してさまざまな種類の操作を選択することを好む場合があります。本当です
...-scharette
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.