Ragioni alla base dell'implementazione non intuitiva di C # String.Split ()


10

In C # se voglio dividere un stringda un altro stringdevo fare qualcosa del genere:

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

Dalla sovraccarica String.Splitdocumentazione MSDN possiamo vedere l'implementazione e perché una tale chiamata deve essere effettuata.

Proveniente da Python , è difficile per me capire correttamente perché sia ​​necessaria una simile chiamata. Voglio dire che avrei potuto usare Regex.Splitper ottenere una sintassi simile all'implementazione di Python, ma avrei dovuto farlo a costo di prestazioni inferiori (tempo di installazione) per qualsiasi cosa semplice .

Quindi in sostanza, la mia domanda è: perché diavolo non possiamo semplicemente fare:

testString.Split("anotherString");

Si noti che non sto suggerendo alcun prototipo né implementazione. Capisco perché non è possibile implementare la versione precedente considerando l'API corrente. Il mio obiettivo era capire perché una simile API avrebbe potuto essere creata considerando i vantaggi che porta la sintassi di cui sopra. A partire da ora, la flessibilità sembra essere l'obiettivo della corrente String.Splitche ha senso, ma ad essere sincero, ho davvero pensato che ci fosse una sorta di guadagno in termini di prestazioni da qualche parte. Immagino di aver sbagliato.


3
Ci stavo pensando anche io. La mia ipotesi è che non hanno fatto molti sforzi per progettare questa unica API. E se si sono resi conto del loro errore, era troppo tardi.
Euforico

@Caleth Puoi approfondire questo. forse mi sbaglio ma non vedo cosa sia ambizioso al riguardo. Perché non posso fare testString.Split(",.;");e testString.Split(new Char [] {',', '.', ';',);che non sono la stessa cosa.
Scharette,

@Euforico L'ho pensato anch'io, ma sarebbe strano. Spero che qualcuno arrivi con una risposta più logica.
scharette,

Puoi iterare su una stringa proprio come un IEnumerable<char>così il prototipo aggiuntivo che stai suggerendo potrebbe apparire ambiguo in alcuni casi (delimiti dall'intera stringa o delimitando da ciascuno dei suoi caratteri?) Solo un'ipotesi.
John Wu,

@JohnWu Forse è una cosa personale, ma per il 99,9% delle occorrenze di sintassi come testString.Split("anotherString");, sono abbastanza fiducioso di dire che il comportamento previsto era delimitare l'intera stringa ( anotherStringin questo caso).
Scharette,

Risposte:


15

A volte è utile suddividere più di un carattere / stringa, quindi l'API ti consente di fornire un array, offrendoti la massima flessibilità. Nel caso di chars, ottieni sia la semplicità della sintassi che la flessibilità poiché il parametro è contrassegnato come in paramsmodo da poter scrivere Split('x')piuttosto che Split(new[]{'x'}).

Quindi perché non esiste un'opzione simile per le stringhe, che consente di scrivere Split("x")?

Questa è forse una sfortunata conseguenza della progettazione dell'API. Inizialmente permetteva solo di dividere i caratteri. La suddivisione su stringhe è stata aggiunta in 2.0, probabilmente perché è più complessa da implementare. Ma non è stato possibile aggiungere String.Split(string)o String.Split(string[])sovraccaricare, poiché ciò renderebbe testString.Split(null)ambigua l'espressione e questo codice non verrà più compilato.

testString.Split(null) è in realtà un linguaggio piuttosto comune dal momento che divide la stringa su spazi bianchi, quindi tale rottura sarebbe troppo diffusa per essere accettabile.

L'utilizzo di un nullparametro come interruttore per comportamenti speciali è generalmente considerato una cattiva progettazione in questi giorni, quindi penso che sia giusto dire che questa API è solo difettosa.

Non c'è Split(string[], Int32)neanche, probabilmente per un motivo simile - sarebbe ambiguo Split(char[], Int32)se il primo parametro fosse null. Ci sono sovraccarichi simili con i StringSplitOptionsparametri, ma questi sono stati tutti aggiunti contemporaneamente in 2.0, quindi nessuna ambiguità è stata introdotta nel codice esistente.

Nota

Per essere chiari, questa è solo la mia ipotesi, non conosco il pensiero reale dei progettisti del framework .net.


1
Bene, è assolutamente utile? Ne dubito. Ed è solo una rottura dell'API, non una ABI.
Deduplicatore

2
@Deduplicator: Split (null) si divide su spazi bianchi, quindi è probabilmente uno dei casi d'uso più comuni per split, anche se è una cattiva progettazione dell'API usare un null come questo.
JacquesB,

1
Penso che @Deduplicator abbia voluto dire che Split(null)è inutile se lo permetti Split(""). Oltre al fatto che consentirebbe una migliore sintassi, quest'ultima è comunque più dettagliata ...
scharette,

1
@scharette: Certo, ma non è possibile cambiare ora, senza interrompere la compatibilità con le versioni precedenti.
Jacques,

1
una nota: con l'attuale anteprima di C # 8, disattivando i tipi di base la nullità String.Split(null)non sarebbe più ambigua, quindi potrebbero aggiungere il sovraccarico
BgrWorker,

2

Non essendo l'autore dei metodi, non so perché sia ​​stata scelta quella serie di sovraccarichi. Tuttavia, ci sono due cose da notare qui:

  1. Se stai dividendo un singolo personaggio, public string[] Split(params char[] separatorpuoi usare la versione) in questo modo:

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

    come char[]è un paramsparametro

  2. Puoi facilmente aggiungere il tuo metodo di estensione qui per ottenere ciò che desideri:

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

    e ora testString.Split("anotherString");funzionerà per te.


1
Grazie per il feedback. Sebbene la tua risposta sia utile e concisa, non posso essere d'accordo con te. Soprattutto il secondo punto. Non c'è un motivo in più per averlo incorporato? Tutto ciò che fa è lasciare che la comunità crei una versione diversa di un metodo che tutti (o quasi) si aspettano di comportarsi allo stesso modo.
Scharette,

Non provando a discutere a proposito, il tuo punto è del tutto valido. Sto solo cercando di capire il motivo dietro questo. Logicamente ci deve essere un motivo storico o di spettacolo ...
scharette,

@scharette: il motivo è rendere il metodo il più generale possibile. Preferibile come trovare la firma del metodo scelto, non funzionerà per più delimitatori. La versione di Microsoft funzionerà per più delimitatori e per il singolo delimitatore.
Robert Harvey,

@RobertHarvey Beh, non sarebbero entrambi possibili? Diciamo che il metodo di estensione nella risposta sopra era parte della Stringclasse, entrambi sarebbero possibili. Ho sbagliato ?
scharette,

Penso che ti stia perdendo il punto. Il tuo sovraccarico consente solo un delimitatore. Il sovraccarico di Microsoft ne consente più di uno. Non è possibile chiamare il sovraccarico più volte e ottenere lo stesso risultato; non è così che funziona.
Robert Harvey,

1

Lingue diverse hanno regole leggermente diverse per conversioni implicite e sovraccarico e .NET Framework è progettato per essere utilizzabile con ognuna di esse. Nel Option Strict Offdialetto di VB.NET, un valore di tipo Stringpuò essere passato a una funzione che prevede un Char[]comportamento equivalente alla chiamata ToCharArray()sulla stringa.

Penso che la cosa sensata da fare sarebbe stata quella di avere nomi separati per Split(che accetta un singolo Charo String) e SplitMulti(che accetterebbe un Char[]o String[]), ma a volte .NET sembra favorire l'uso del sovraccarico da solo per scegliere diversi tipi di operazioni. Sfortunatamente, non conosco alcun modo di utilizzare String.Splitper adattarsi a scenari di utilizzo che richiederebbero la distinzione di diversi tipi di delimitatori se non dividendo separatamente su ciascuno di essi.

Un'altra omissione è un'opzione per preservare i delimitatori, includendoli alla fine della stringa precedente, o all'inizio della stringa seguente, o avendo elementi di array con numeri dispari essere delimitatori mentre gli elementi con numeri pari sono le cose tra loro.


1
.NET a volte sembra favorire l'utilizzo del sovraccarico da solo per scegliere diversi tipi di operazioni. Così vero ...
Scharette,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.