Sezgisel olmayan C # String.Split () uygulamasının arkasındaki nedenler


10

C # stringbaşka bir bölmek istiyorsanız stringben böyle bir şey yapmak zorunda:

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

Aşırı yüklenmiş String.SplitMSDN Dokümantasyonundan uygulamayı ve neden böyle bir çağrı yapılması gerektiğini görebiliriz.

Python'dan geliyor, böyle bir çağrının neden gerekli olduğunu doğru bir şekilde anlamak benim için zor. Yani Regex.SplitPython uygulamasından benzer bir sözdizimi elde etmek için kullanabilirsiniz ama basit bir şey için daha az performans (kurulum süresi) pahasına bunu yapmak zorunda kalacaktı .

Yani temelde sorum şu: Niye yapamıyoruz?

testString.Split("anotherString");

Herhangi bir prototip veya uygulama önermediğimi unutmayın. Mevcut API'yı dikkate alarak yukarıdaki sürümü neden uygulayamadığınızı anlıyorum. Amacım, yukarıdaki sözdiziminin getirdiği fayda göz önüne alınarak böyle bir API'nin neden oluşturulduğunu anlamaktı. Şu an itibariyle, esneklikString.Split mantıklı olan akımın hedefi gibi görünüyor , ama dürüst olmak gerekirse bir yerlerde bir tür performans kazancı olduğunu düşündüm. Sanırım yanılmışım.


3
Ben de bunu düşünüyordum. Benim spekülasyonum, bu tek API'yi tasarlamak için çok çaba sarf etmemeleri. Ve eğer hatalarını fark ederlerse, çok geç kalmıştı.
Euphoric

@Caleth Bunu biraz ayrıntılandırabilir misin? belki yanılıyorum ama bu konuda ne olduğunu göremiyorum. Neden yapamıyorum testString.Split(",.;");ve testString.Split(new Char [] {',', '.', ';',);bunlar aynı şey değil.
scharette

@Euthoric Ben de öyle düşündüm, ama bu çok garip olurdu. Umarım birisi daha mantıklı bir cevapla gelir.
scharette

Bir dize üzerinde olduğu gibi yineleyebilirsiniz, IEnumerable<char>böylece önerdiğiniz ek prototip bazı durumlarda belirsiz görünebilir (tüm dizeyle sınırlandırıyor musunuz veya karakterlerinin her biri ile sınırlanıyor musunuz?) Sadece bir tahmin.
John Wu

@JohnWu Belki kişisel bir şeydir, ancak sözdizimi oluşumlarının% 99,9'u için testString.Split("anotherString");, beklenen davranışın tüm dize ( anotherStringbu durumda) sınırlamak olduğunu söylemek oldukça eminim .
scharette

Yanıtlar:


15

Bazen birden fazla karakter / karakter dizisine bölmek yararlı olabilir, bu nedenle API size maksimum esneklik sağlayan bir dizi sunmanıza izin verir. S durumunda char, parametre yerine paramsyazabileceğiniz gibi işaretlendiğinden, sözdizimi ve esnekliğin basitliğini elde edersiniz .Split('x')Split(new[]{'x'})

Öyleyse neden yazmanıza izin veren dizeler için benzer bir seçenek yok Split("x")?

Bu belki de API'nın nasıl tasarlandığının talihsiz bir sonucudur. Başlangıçta sadece karakterlerin bölünmesine izin verdi. Dizelerde ayırma, muhtemelen uygulanması daha karmaşık olduğu için 2.0'da eklendi. Ancak, ekleme String.Split(string)veya String.Split(string[])aşırı yükleme yapmak mümkün değildi , çünkü bu ifadeyi testString.Split(null)belirsizleştirecek ve bu kod artık derlenmeyecektir.

testString.Split(null) aslında dizgiyi boşlukta ayırdığı için oldukça yaygın bir deyimdir, bu nedenle bu kırılma kabul edilemeyecek kadar yaygın olacaktır.

nullÖzel davranış için bir anahtar olarak bir -parametre kullanmak , bu günlerde genellikle kötü tasarım olarak kabul edilir, bu yüzden bu API'nın sadece kusurlu olduğunu söylemek adil olur.

Hiçbir yoktur Split(string[], Int32)muhtemelen benzer bir nedenden dolayı, ya da - ile belirsiz olacağını Split(char[], Int32)ilk parametre ise null. Orada olan ile benzer aşırı yükler StringSplitOptionsparametreleri, ancak hiçbir belirsizlik mevcut kod tanıtıldı yüzden bunların hepsi, 2.0 aynı anda eklenmiştir.

Not

Açık olmak gerekirse, bu sadece benim hipotezim .net çerçeve tasarımcıları tarafından gerçek düşünceyi bilmiyorum.


1
Peki, bu hiç faydalı mı? Şüphe edin. Ve bu sadece bir API sonu, ABI değil.
Tekilleştirici

2
@Deduplicator: Split (null) boşluk üzerinde bölünür, bu nedenle böyle bir null kullanmak kötü API tasarımı olsa da, muhtemelen split için en yaygın kullanım durumlarından biridir.
JacquesB

1
@Deduplicator Split(null)izin verirseniz bunun işe yaramaz olduğunu söylemek istediğini düşünüyorum Split(""). Bir şekilde daha iyi bir sözdizimine izin vermesinin yanı sıra, ikincisi zaten daha ayrıntılı ...
scharette

1
@scharette: Elbette, ancak geriye dönük uyumluluğu bozmadan değiştirmek mümkün değil.
JacquesB

1
bir not: mevcut C # 8 önizlemesiyle, taban türlerini kapatarak nullabilite String.Split(null)artık belirsiz olmayacak, bu yüzden aşırı yük ekleyebilirler
BgrWorker

2

Metodların yazarı olmayan bu aşırı yük setinin neden seçildiğini bilmiyorum. Ancak, burada dikkat edilmesi gereken iki şey vardır:

  1. Tek bir karaktere bölüyorsanız, public string[] Split(params char[] separator) sürümü şu şekilde kullanılabilir:

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

    olarak char[]a, paramsparametresi.

  2. İstediğinizi elde etmek için buraya kendi genişletme yönteminizi kolayca ekleyebilirsiniz:

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

    ve şimdi testString.Split("anotherString");sizin için çalışacaktır.


1
Geri dönüşünüz için teşekkür ederiz. Cevabınız yararlı ve özlü olmasına rağmen, sizinle aynı fikirde değilim. Özellikle ikinci nokta. Yerleşik olması için bir neden daha değil mi? Tek yaptığı, topluluğun, herkesin (veya neredeyse herkesin) aynı şekilde davranmasını beklediği bir yöntemin farklı bir versiyonunu oluşturmasına izin vermektir.
scharette

Bu arada tartışmaya çalışmamanız gereken nokta tamamen geçerli. Sadece bunun nedenini anlamaya çalışıyorum. Mantıksal olarak tarihi veya performans nedeni olmalı ...
scharette

@scharette: Nedeni yöntemi mümkün olduğunca genel bir amaç haline getirmektir. Seçtiğiniz yöntem imzasını bulduğunuz kadar çok sayıda sınırlayıcı için çalışmaz. Microsoft'un sürümü, tek sınırlayıcınızın yanı sıra birden çok sınırlayıcı için de çalışır.
Robert Harvey

@RobertHarvey Her ikisi de mümkün olmaz mıydı? Diyelim ki yukarıdaki cevaptaki uzatma yöntemi Stringsınıfın bir parçasıydı , her ikisi de mümkün olurdu. Yanlış mıyım ?
scharette

Bence bu noktayı kaçırıyorsun. Aşırı yükünüz yalnızca bir sınırlayıcıya izin verir. Microsoft'un aşırı yüklenmesi birden fazla işleme izin verir. Aşırı yüklemenizi birden çok kez arayamaz ve aynı sonucu elde edemezsiniz; bu böyle çalışmaz.
Robert Harvey

1

Farklı diller örtük dönüşümler ve aşırı yükleme için biraz farklı kurallara sahiptir ve .NET Framework bunlardan herhangi biri ile kullanılabilecek şekilde tasarlanmıştır. Gelen Option Strict OffVB.NET ağızlarıyla, tip bir değer String, bir bekleyen bir işleve geçirilebilir Char[]çağrılmasına davranışı ile eşdeğer ToCharArray()ipe.

Yapmak için mantıklı bir şey Split(tek bir Charya da kabul eder String) ve SplitMulti(hangi bir Char[]ya da kabul eder) için ayrı isimler olurdu String[], ama .NET bazen farklı işlemleri seçmek için yalnız aşırı yükleme kullanarak tercih gibi görünüyor. Ne yazık ki, String.Splither biri ayrı ayrı bölmekten başka farklı sınırlayıcıları ayırt etmeyi gerektiren herhangi bir kullanım senaryosunu barındırmak için kullanmanın bir yolunu bilmiyorum .

Bir başka ihmal, bir önceki dizenin sonuna ya da bir sonraki dizenin başlangıcına dahil olan sınırlayıcıları korumak ya da tek sayılı dizi öğelerinin aradaki şeyler olduğu halde tek sayılı dizi öğelerinin sınırlayıcı olması için bir seçenektir.


1
.NET bazen farklı işlemleri seçmek için aşırı yüklemeyi kullanmayı tercih eder. Çok doğru ...
scharette
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.