Lý do đằng sau việc triển khai C # String.Split () không trực quan


11

Trong C # nếu tôi muốn tách một stringngười khác, stringtôi phải làm một cái gì đó như thế:

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

Từ String.SplitTài liệu MSDN quá tải, chúng ta có thể thấy việc triển khai và tại sao phải thực hiện một cuộc gọi như vậy.

Đến từ Python , thật khó để tôi hiểu chính xác tại sao cần một cuộc gọi như vậy. Ý tôi là tôi có thể sử dụng Regex.Splitđể có được một cú pháp tương tự như cách triển khai của Python nhưng tôi sẽ phải làm điều đó với chi phí ít hiệu năng hơn (thời gian thiết lập) cho mọi thứ đơn giản .

Về cơ bản, câu hỏi của tôi là tại sao chúng ta không thể làm:

testString.Split("anotherString");

Lưu ý rằng tôi không đề xuất bất kỳ nguyên mẫu cũng như thực hiện. Tôi hiểu lý do tại sao bạn không thể triển khai phiên bản trên khi xem xét API hiện tại. Mục tiêu của tôi là hiểu lý do tại sao một API như vậy có thể được tạo ra khi xem xét lợi ích mà cú pháp trên mang lại. Đến bây giờ, tính linh hoạt dường như là mục tiêu của hiện tại String.Splitcó ý nghĩa, nhưng thành thật mà nói tôi thực sự nghĩ rằng có một số loại hiệu suất đạt được ở đâu đó. Tôi đoán tôi đã sai.


3
Tôi đã suy nghĩ về điều này quá. Suy đoán của tôi là họ đã không nỗ lực nhiều trong việc thiết kế một API này. Và nếu họ nhận ra sai lầm của mình thì đã quá muộn.
Euphoric

@Caleth Bạn có thể giải thích về điều này. có thể tôi sai nhưng tôi không thấy những gì đáng tiếc về nó. Tại sao tôi không thể làm testString.Split(",.;");testString.Split(new Char [] {',', '.', ';',);đó không phải là điều tương tự.
scharette

@Euphoric Tôi cũng nghĩ vậy, nhưng điều đó thật kỳ quặc. Hy vọng ai đó đi kèm với một câu trả lời logic hơn.
scharette

Bạn có thể lặp lại một chuỗi giống như một IEnumerable<char>nguyên mẫu bổ sung mà bạn đang đề xuất có thể xuất hiện mơ hồ trong một số trường hợp nhất định (bạn có phân định toàn bộ chuỗi hoặc phân định theo từng ký tự của chuỗi không?) Chỉ là một phỏng đoán.
John Wu

@JohnWu Có thể đó là một việc cá nhân, nhưng với 99,9% số lần xuất hiện của cú pháp như thế testString.Split("anotherString");, tôi khá tự tin để nói rằng hành vi dự kiến ​​là phân định trên toàn bộ chuỗi ( anotherStringtrong trường hợp này).
scharette

Câu trả lời:


15

Đôi khi, việc chia nhỏ trên nhiều char / chuỗi là hữu ích, do đó API cho phép bạn cung cấp một mảng, mang lại cho bạn sự linh hoạt tối đa. Trong trường hợp của chars, bạn có được cả sự đơn giản của cú pháp và tính linh hoạt do tham số được đánh dấu là paramsđể bạn có thể viết Split('x')chứ không phải Split(new[]{'x'}).

Vậy tại sao không có tùy chọn tương tự cho chuỗi, cho phép bạn viết Split("x")?

Đây có lẽ là một hậu quả đáng tiếc về cách API được thiết kế. Ban đầu nó chỉ cho phép tách trên ký tự. Chia tách trên các chuỗi đã được thêm vào trong 2.0, có lẽ vì nó phức tạp hơn để thực hiện. Nhưng không thể thêm String.Split(string)hoặc String.Split(string[])quá tải, vì điều này sẽ làm cho biểu thức testString.Split(null)mơ hồ và mã này sẽ không được biên dịch nữa.

testString.Split(null) thực sự là một thành ngữ khá phổ biến vì nó phân tách chuỗi trên khoảng trắng, do đó sự phá vỡ như vậy sẽ quá phổ biến để có thể chấp nhận được.

Ngày nay, việc sử dụng một nulltham số như một công tắc cho hành vi đặc biệt thường bị coi là thiết kế tồi, vì vậy tôi nghĩ thật công bằng khi nói API này chỉ là thiếu sót.

Không có Split(string[], Int32)một trong hai, có lẽ vì một lý do tương tự - sẽ không rõ ràng Split(char[], Int32)nếu tham số đầu tiên là null. Có quá tải tương tự với các StringSplitOptionsthông số, nhưng tất cả những được bổ sung cùng lúc ở 2.0, vì vậy không mơ hồ được giới thiệu vào mã hiện.

Ghi chú

Để rõ ràng, đây chỉ là giả thuyết của tôi, tôi không biết suy nghĩ thực tế của các nhà thiết kế khung .net.


1
Vâng, điều đó có hữu ích không? Nghi ngờ điều đó. Và nó chỉ là một sự phá vỡ API, không phải là một ABI.
Ded repeatator

2
@Ded repeatator: Split (null) phân tách trên khoảng trắng, vì vậy đây có thể là một trong những trường hợp sử dụng phổ biến nhất để phân tách, mặc dù đó là thiết kế API xấu khi sử dụng null như thế này.
JacquesB

1
Tôi nghĩ rằng @Ded repeatator muốn nói rằng điều đó Split(null)là vô ích nếu bạn cho phép Split(""). Bên cạnh thực tế là nó sẽ cho phép một cú pháp tốt hơn, dù sao thì nó cũng dài dòng hơn ...
scharette

1
@scharette: Chắc chắn, nhưng không thể thay đổi ngay bây giờ, mà không phá vỡ tính tương thích ngược.
JacquesB

1
một lưu ý: với bản xem trước C # 8 hiện tại, bằng cách tắt tính năng vô hiệu của các loại cơ sở String.Split(null)sẽ không còn mơ hồ, vì vậy chúng có thể thêm quá tải
BgrWorker

2

Không phải là tác giả của các phương thức, tôi không biết tại sao tập hợp quá tải đó lại được chọn. Tuy nhiên, có hai điều cần lưu ý ở đây:

  1. Nếu bạn đang phân tách trên một ký tự, thì public string[] Split(params char[] separatorphiên bản) có thể được sử dụng như vậy:

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

    như char[]là một paramstham số.

  2. Bạn có thể dễ dàng thêm phương thức tiện ích mở rộng của riêng mình vào đây để đạt được những gì bạn muốn:

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

    và bây giờ testString.Split("anotherString");sẽ làm việc cho bạn.


1
Cảm ơn vì bạn đã phản hồi. Mặc dù câu trả lời của bạn rất hữu ích và ngắn gọn, tôi không thể đồng ý với bạn. Đặc biệt là điểm thứ hai. Không phải là một lý do nữa để tích hợp nó sao? Tất cả những gì nó làm là để cộng đồng tạo ra phiên bản khác nhau của một phương thức mà mọi người (hoặc gần như tất cả mọi người) mong đợi sẽ hành xử theo cùng một cách.
scharette

Không cố gắng tranh luận bằng cách này, quan điểm của bạn là hoàn toàn hợp lệ. Chỉ cần cố gắng để hiểu lý do đằng sau này. Theo logic thì phải có một lý do lịch sử hoặc hiệu suất ...
scharette

@scharette: Lý do là để làm cho phương pháp càng có mục đích chung càng tốt. Nếu bạn tìm thấy chữ ký phương thức đã chọn, nó sẽ không hoạt động đối với nhiều dấu phân cách. Phiên bản của Microsoft sẽ hoạt động cho nhiều dấu phân cách cũng như dấu phân cách đơn của bạn.
Robert Harvey

@RobertHarvey Cả hai sẽ không thể? Giả sử phương thức mở rộng trong câu trả lời trên là một phần của Stringlớp, cả hai đều có thể. Tôi có lầm không ?
scharette

Tôi nghĩ rằng bạn đang thiếu điểm. Quá tải của bạn chỉ cho phép một dấu phân cách. Quá tải của Microsoft cho phép nhiều hơn một. Bạn không thể gọi quá tải của mình nhiều lần và đạt được kết quả tương tự; đó không phải là cách nó hoạt động.
Robert Harvey

1

Các ngôn ngữ khác nhau có một số quy tắc khác nhau để chuyển đổi ngầm và quá tải, và .NET Framework được thiết kế để có thể sử dụng được với bất kỳ ngôn ngữ nào. Trong Option Strict Offphương ngữ của VB.NET, một giá trị của loại Stringcó thể được truyền cho một hàm mong đợi một Char[]hành vi tương đương với việc gọi ToCharArray()trên chuỗi.

Tôi nghĩ rằng điều hợp lý để làm là có các tên riêng cho Split(chấp nhận một Charhoặc String) và SplitMulti(chấp nhận một Char[]hoặc String[]), nhưng đôi khi .NET dường như thích sử dụng quá tải một mình để chọn các loại hoạt động khác nhau. Thật không may, tôi biết không có cách nào để sử dụng String.Splitđể phù hợp với bất kỳ kịch bản sử dụng nào sẽ yêu cầu phân biệt các loại dấu phân cách khác nhau ngoài việc tách riêng từng loại.

Một thiếu sót khác là một tùy chọn để bảo toàn các dấu phân cách, bao gồm cả chúng ở cuối chuỗi trước hoặc ở đầu chuỗi sau hoặc có các phần tử mảng số lẻ là dấu phân cách trong khi các phần tử được đánh số chẵn là những thứ nằm giữa chúng.


1
.NET đôi khi dường như ủng hộ việc sử dụng quá tải một mình để chọn các loại hoạt động khác nhau. Thật vậy ...
scharette
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.