Gründe für die nicht intuitive Implementierung von C # String.Split ()

11

Wenn ich in C # eine stringdurch eine andere teilen möchte, muss stringich so etwas tun:

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

Aus der überladenen String.SplitMSDN-Dokumentation können wir die Implementierung und den Grund für einen solchen Aufruf ersehen.

Ich komme aus Python und kann nur schwer richtig verstehen, warum ein solcher Aufruf erforderlich ist. Ich meine, ich könnte Regex.Spliteine ähnliche Syntax wie die Python-Implementierung verwenden, aber ich müsste dies auf Kosten einer geringeren Leistung (Einrichtungszeit) für alles Einfache tun .

Meine Frage ist also, warum zum Teufel können wir das nicht einfach tun:

testString.Split("anotherString");

Beachten Sie, dass ich weder einen Prototyp noch eine Implementierung vorschlage. Ich verstehe, warum Sie die obige Version unter Berücksichtigung der aktuellen API nicht implementieren konnten. Mein Ziel war es zu verstehen, warum eine solche API unter Berücksichtigung des Nutzens der obigen Syntax hätte erstellt werden können. Ab sofort scheint Flexibilität das Ziel der Strömung zu sein, String.Splitwas Sinn macht, aber um ehrlich zu sein, dachte ich wirklich, dass es irgendwo eine Art Leistungsgewinn gibt. Ich schätze ich lag falsch.

scharette
quelle
3
Ich habe auch darüber nachgedacht. Ich spekuliere, dass sie sich nicht viel Mühe gegeben haben, diese eine API zu entwerfen. Und wenn sie ihren Fehler bemerkten, war es zu spät.
Euphoric
@ Caleth Kannst du das näher erläutern? Vielleicht irre ich mich, aber ich sehe nicht, was daran ambivalent ist. Warum kann ich das nicht testString.Split(",.;");und testString.Split(new Char [] {',', '.', ';',);was ist nicht dasselbe?
scharette
@Euphoric Ich habe das auch gelernt, aber das wäre so seltsam. Hoffe, jemand kommt mit einer logischeren Antwort.
scharette
Sie können eine Zeichenfolge genau wie eine durchlaufen, IEnumerable<char>sodass der von Ihnen vorgeschlagene zusätzliche Prototyp in bestimmten Fällen möglicherweise nicht eindeutig ist (begrenzen Sie die gesamte Zeichenfolge oder die einzelnen Zeichen?). Nur eine Vermutung.
John Wu
@ JohnWu Vielleicht ist es eine persönliche Sache, aber für 99,9% der Syntaxvorkommen wie testString.Split("anotherString");bin ich ziemlich zuversichtlich zu sagen, dass das erwartete Verhalten darin bestand, die gesamte Zeichenfolge ( anotherStringin diesem Fall) abzugrenzen .
scharette

Antworten:

15

Manchmal ist es sinnvoll, mehr als ein Zeichen / eine Zeichenfolge aufzuteilen, sodass Sie mit der API ein Array bereitstellen können, das Ihnen maximale Flexibilität bietet. Im Fall von chars erhalten Sie sowohl eine einfache Syntax als auch Flexibilität, da der Parameter als markiert ist, paramsdamit Sie schreiben können Split('x')und nicht Split(new[]{'x'}).

Warum gibt es keine ähnliche Option für Zeichenfolgen, mit der Sie schreiben können Split("x")?

Dies ist möglicherweise eine unglückliche Folge der Gestaltung der API. Anfangs war es nur erlaubt, Zeichen aufzuteilen. Das Aufteilen auf Zeichenfolgen wurde in 2.0 hinzugefügt, wahrscheinlich weil die Implementierung komplexer ist. Das Hinzufügen String.Split(string)oder String.Split(string[])Überladen war jedoch nicht möglich , da dies den Ausdruck testString.Split(null)mehrdeutig machen und dieser Code nicht mehr kompilieren würde.

testString.Split(null) ist eigentlich eine ziemlich verbreitete Redewendung, da sie die Zeichenfolge in Leerzeichen aufteilt, sodass ein solcher Bruch zu weit verbreitet wäre, um akzeptabel zu sein.

Die Verwendung eines nullParameters als Schalter für spezielles Verhalten wird heutzutage allgemein als schlechtes Design angesehen. Ich denke, es ist fair zu sagen, dass diese API nur fehlerhaft ist.

Es gibt auch keine Split(string[], Int32), wahrscheinlich aus einem ähnlichen Grund - es wäre mehrdeutig, Split(char[], Int32)wenn der erste Parameter ist null. Es gibt ähnliche Überladungen mit den StringSplitOptionsParametern, aber diese wurden alle gleichzeitig in 2.0 hinzugefügt, sodass im vorhandenen Code keine Mehrdeutigkeit eingeführt wurde.

Hinweis

Um klar zu sein, dies ist nur meine Hypothese, ich kenne das tatsächliche Denken der .net-Framework-Designer nicht.

JacquesB
quelle
1
Nun, ist das überhaupt nützlich? Zweifle daran. Und es ist nur eine API-Unterbrechung, keine ABI-Unterbrechung.
Deduplikator
2
@Deduplicator: Split (null) wird auf Leerzeichen aufgeteilt, daher ist dies wahrscheinlich einer der häufigsten Anwendungsfälle für das Teilen, obwohl es ein schlechtes API-Design ist, eine solche Null zu verwenden.
JacquesB
1
Ich denke, @Deduplicator wollte sagen, dass Split(null)das nutzlos ist, wenn Sie es erlauben Split(""). Abgesehen von der Tatsache, dass es eine viel bessere Syntax ermöglichen würde, ist letztere sowieso ausführlicher ...
scharette
1
@scharette: Sicher, aber es ist jetzt nicht möglich, Änderungen vorzunehmen, ohne die Abwärtskompatibilität zu beeinträchtigen.
JacquesB
1
Ein Hinweis: Mit der aktuellen C # 8-Vorschau String.Split(null)wäre das Deaktivieren der Nullbarkeit von Basistypen nicht mehr mehrdeutig, sodass sie die Überlastung hinzufügen könnten
BgrWorker
2

Da ich nicht der Autor der Methoden bin, weiß ich nicht, warum diese Überladungen ausgewählt wurden. Hier sind jedoch zwei Dinge zu beachten:

  1. Wenn Sie auf ein einzelnes Zeichen public string[] Split(params char[] separatoraufteilen, kann die ) Version folgendermaßen verwendet werden:

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

    wie das char[]ist ein paramsParameter.

  2. Sie können hier ganz einfach Ihre eigene Erweiterungsmethode hinzufügen, um das zu erreichen, was Sie möchten:

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

    und jetzt testString.Split("anotherString");wird für dich arbeiten.

David Arno
quelle
1
Danke für die Rückmeldung. Obwohl Ihre Antwort hilfreich und prägnant ist, kann ich Ihnen nicht zustimmen. Besonders der zweite Punkt. Ist das nicht noch ein Grund, es eingebaut zu haben? Alles, was es tut, ist, die Community eine andere Version einer Methode erstellen zu lassen, von der jeder (oder fast jeder) erwartet, dass sie sich gleich verhält.
scharette
Sie versuchen übrigens nicht zu debattieren, aber Ihr Punkt ist völlig gültig. Ich versuche nur, den Grund dafür zu verstehen. Logischerweise muss es einen historischen oder Performance-Grund geben ...
scharette
@scharette: Der Grund ist, die Methode so allgemein wie möglich zu gestalten. So bevorzugt Sie die von Ihnen gewählte Methodensignatur finden, funktioniert sie nicht für mehrere Trennzeichen. Die Microsoft-Version funktioniert sowohl für mehrere Trennzeichen als auch für Ihr einzelnes Trennzeichen.
Robert Harvey
@ RobertHarvey Nun, wären nicht beide möglich? Angenommen, die Erweiterungsmethode in der obigen Antwort war Teil der StringKlasse, beides wäre möglich. Liege ich falsch ?
scharette
Ich denke, Sie verpassen den Punkt. Ihre Überlastung erlaubt nur ein Trennzeichen. Die Überlastung von Microsoft ermöglicht mehr als eine. Sie können Ihre Überlastung nicht mehrmals aufrufen und das gleiche Ergebnis erzielen. So funktioniert das nicht.
Robert Harvey
1

Verschiedene Sprachen haben etwas unterschiedliche Regeln für implizite Konvertierungen und Überladungen, und .NET Framework ist so konzipiert, dass es mit jeder von ihnen verwendet werden kann. Im Option Strict OffDialekt von VB.NET kann ein Wert vom Typ Stringan eine Funktion übergeben werden, die ein Char[]Verhalten erwartet , das dem Aufrufen ToCharArray()der Zeichenfolge entspricht.

Ich denke, das Vernünftige wäre gewesen, separate Namen für Split(die ein einzelnes Charoder akzeptieren String) und SplitMulti(die ein Char[]oder akzeptieren würden String[]) zu haben, aber .NET scheint manchmal die Verwendung von Überladung allein zu bevorzugen, um verschiedene Arten von Operationen auszuwählen. Leider kenne ich keine Möglichkeit, Verwendungsszenarien String.Splitzu berücksichtigen, bei denen verschiedene Arten von Trennzeichen unterschieden werden müssten, außer durch getrennte Aufteilung.

Eine weitere Auslassung ist die Option, Trennzeichen beizubehalten, entweder am Ende der vorhergehenden Zeichenfolge oder am Anfang der folgenden Zeichenfolge, oder ungeradzahlige Array-Elemente als Trennzeichen zu verwenden, während geradzahlige Elemente die Dinge zwischen ihnen sind.

Superkatze
quelle
1
.NET scheint manchmal die alleinige Verwendung von Überladung zu bevorzugen, um verschiedene Arten von Vorgängen auszuwählen. So wahr ...
scharette