เหตุผลเบื้องหลังการใช้งาน C # String.Split () ที่ไม่เข้าใจง่าย


10

ใน C # ถ้าฉันต้องการแยก a stringอีกอันstringฉันต้องทำสิ่งนั้น:

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

จากString.Splitเอกสาร MSDN ที่มีการโอเวอร์โหลดเราสามารถเห็นการใช้งานและสาเหตุที่ต้องทำการโทร

มาจากPythonมันยากสำหรับฉันที่จะเข้าใจอย่างถูกต้องว่าทำไมจึงต้องมีการโทร ฉันหมายความว่าฉันสามารถใช้Regex.Splitเพื่อให้ได้ไวยากรณ์ที่คล้ายกันมากกว่าการดำเนินการของงูใหญ่ แต่ผมจะต้องทำมันที่ค่าใช้จ่ายของประสิทธิภาพการทำงานน้อยกว่า (เวลาการติดตั้ง) สำหรับอะไรที่เรียบง่าย

โดยพื้นฐานแล้วคำถามของฉันคือทำไมเราทำไม่ได้:

testString.Split("anotherString");

โปรดทราบว่าฉันไม่ได้แนะนำต้นแบบหรือการนำไปใช้ใด ๆ ฉันเข้าใจว่าทำไมคุณไม่สามารถใช้เวอร์ชันด้านบนเนื่องจาก API ปัจจุบัน เป้าหมายของฉันคือเข้าใจว่าทำไม API ดังกล่าวจึงถูกสร้างขึ้นโดยคำนึงถึงประโยชน์ที่ไวยากรณ์ข้างต้นนำมา ณ ตอนนี้ความยืดหยุ่นดูเหมือนจะเป็นเป้าหมายของกระแสString.Splitที่เข้าท่า แต่ตามจริงแล้วฉันคิดว่าจริงๆแล้วมีการแสดงบางอย่างที่ได้รับบ้าง ฉันเดาว่าฉันผิด


3
ฉันก็คิดถึงเรื่องนี้เช่นกัน การคาดเดาของฉันคือพวกเขาไม่ได้ใช้ความพยายามอย่างมากในการออกแบบ API นี้ และหากพวกเขาตระหนักถึงความผิดพลาดมันก็สายเกินไป
ร่าเริง

@Caleth คุณช่วยอธิบายเรื่องนี้ได้ไหม บางทีฉันผิด แต่ฉันไม่เห็นว่ามีอะไรเกี่ยวกับเรื่องนี้มากเกินไป ทำไมฉันถึงทำไม่ได้testString.Split(",.;");และtestString.Split(new Char [] {',', '.', ';',);มันไม่เหมือนกัน
scharette

@Eurhoric ฉันก็เช่นกัน แต่ก็จะแปลกมาก หวังว่าใครบางคนมาพร้อมกับคำตอบเชิงตรรกะมากขึ้น
scharette

คุณสามารถวนซ้ำสตริงได้IEnumerable<char>ดังนั้นต้นแบบเพิ่มเติมที่คุณแนะนำอาจปรากฏชัดเจนในบางกรณี (คุณคั่นด้วยสตริงทั้งหมดหรือกำหนดขอบเขตโดยอักขระแต่ละตัว?) เพียงเดา
John Wu

@ 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พารามิเตอร์เป็นสวิตช์สำหรับพฤติกรรมพิเศษโดยทั่วไปถือว่าเป็นการออกแบบที่ไม่ดีดังนั้นฉันคิดว่ามันยุติธรรมที่จะพูดว่า API นี้มีข้อบกพร่อง

ไม่มีSplit(string[], Int32)อย่างใดอย่างหนึ่งอาจจะเป็นเหตุผลที่คล้ายกัน - มันจะไม่ชัดเจนด้วยถ้าพารามิเตอร์แรกคือSplit(char[], Int32) nullมีอยู่ทับถมคล้ายกับStringSplitOptionsพารามิเตอร์ แต่เหล่านี้ถูกเพิ่มเข้ามาตลอดในเวลาเดียวกันใน 2.0 จึงไม่มีความคลุมเครือเป็นที่รู้จักในรหัสที่มีอยู่

บันทึก

เพื่อความชัดเจนนี่เป็นเพียงสมมติฐานของฉันฉันไม่ทราบความคิดที่แท้จริงของนักออกแบบกรอบงาน. net


1
มีประโยชน์หรือไม่? สงสัยเลยว่า และเป็นเพียงการแบ่ง API ไม่ใช่ ABI
Deduplicator

2
@Dupuplicator: Split (null) แยกบนช่องว่างดังนั้นอาจเป็นกรณีการใช้งานที่พบบ่อยที่สุดสำหรับการแบ่งแม้ว่าจะเป็นการออกแบบ API ที่ไม่ดีให้ใช้ null เช่นนี้
JacquesB

1
ผมคิดว่า @Deduplicator อยากจะบอกว่าไม่มีประโยชน์ถ้าคุณอนุญาตSplit(null) Split("")นอกจากนี้ความจริงที่ว่ามันจะช่วยให้มีรูปแบบที่ดีกว่าไวยากรณ์หลังเป็น verbose มากขึ้นต่อไป ...
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 จะทำงานสำหรับตัวคั่นหลายตัวรวมถึงตัวคั่นเดียวของคุณ
Robert Harvey

@RobertHarvey ทีนี้ทั้งคู่คงไม่ได้เหรอ? สมมติว่าวิธีการขยายในคำตอบข้างต้นเป็นส่วนหนึ่งของStringชั้นเรียนทั้งสองจะเป็นไปได้ ฉันผิดหรือเปล่า?
scharette

ฉันคิดว่าคุณไม่มีจุด เกินพิกัดของคุณอนุญาตเพียงหนึ่งตัวคั่น เกินพิกัดของ Microsoft อนุญาตมากกว่าหนึ่ง คุณไม่สามารถเรียกโอเวอร์โหลดของคุณหลายครั้งและบรรลุผลลัพธ์เดียวกัน นั่นไม่ใช่วิธีการทำงาน
Robert Harvey

1

ภาษาที่แตกต่างกันมีกฎที่แตกต่างกันบ้างสำหรับการแปลงและการโอเวอร์โหลดโดยนัยและ. NET Framework ได้รับการออกแบบให้ใช้งานได้กับทุกภาษา ในOption Strict Offภาษาของ VB.NET ค่าของชนิดStringอาจถูกส่งผ่านไปยังฟังก์ชันซึ่งคาดว่า a Char[]กับลักษณะการทำงานเทียบเท่ากับการเรียกToCharArray()บนสายอักขระ

ผมคิดว่าสิ่งที่เหมาะสมที่จะทำจะได้รับที่จะมีชื่อที่แยกต่างหากสำหรับSplit(ซึ่งยอมรับเดียวCharหรือString) และSplitMulti(ซึ่งจะยอมรับChar[]หรือString[]) แต่ .NET บางครั้งดูเหมือนว่าจะชอบใช้มากไปคนเดียวที่จะเลือกชนิดที่แตกต่างกันของการดำเนินงาน น่าเสียดายที่ฉันรู้ว่าไม่มีทางที่จะใช้String.Splitเพื่อรองรับสถานการณ์การใช้งานใด ๆ ที่จะต้องแยกความแตกต่างของตัวคั่นอื่น ๆ โดยแยกออกจากกัน

การละเว้นก็คือตัวเลือกในการรักษาตัวคั่นไม่ว่าจะรวมไว้ที่ส่วนท้ายของสตริงก่อนหน้าหรือที่จุดเริ่มต้นของสตริงต่อไปนี้หรือมีองค์ประกอบอาร์เรย์เลขคี่เป็นตัวคั่นในขณะที่องค์ประกอบเลขคู่เป็นสิ่งที่อยู่ระหว่างพวกเขา


1
บางครั้ง. NET ดูเหมือนว่าจะนิยมใช้การโหลดมากเกินไปเพียงอย่างเดียวเพื่อเลือกการทำงานประเภทต่างๆ จริงอยู่ ...
scharette
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.