[Lưu ý: Dưới đây là một chút nặng về cú pháp và quy ước của nó, chẳng hạn như trích dẫn các quy tắc FxCop, bởi vì đây là nền tảng của tôi, nhưng mục đích của cuộc thảo luận này là không biết ngôn ngữ và các ví dụ mã được sử dụng thường được coi là mã giả. - Mike]
Tôi nghĩ rằng tất cả chúng ta sẽ đồng ý rằng các lớp thường được thiết kế sao cho các thể hiện đối tượng của chúng là bất biến ở bất cứ nơi nào thực tế và kết quả của việc gọi các thành viên của lớp sẽ không có tác dụng phụ, càng nhiều càng tốt.
Tuy nhiên, các quy ước đặt tên lịch sử có xu hướng sử dụng giọng nói tích cực: 'GetS Something', 'DoSome Breath', v.v. và điều này là tốt bởi vì nó nêu rõ hành động mà thành viên lớp sẽ thực hiện.
Tuy nhiên, bây giờ tôi bắt đầu nghĩ rằng các thành viên đôi khi có thể (hoặc có thể thường xuyên) được hưởng lợi bằng cách được đặt tên ở thì quá khứ để ám chỉ rằng một giá trị được trả về mà không ảnh hưởng đến đối tượng được tham chiếu.
Ví dụ, đối với một phương thức hoán chuyển một mảng, các kiểu đặt tên hiện tại có thể có tên là 'Array.Transpose', nhưng nếu thành viên này trả về một mảng mới , mà không chuyển đổi đối tượng được tham chiếu, thì tôi nghĩ rằng việc gọi nó là 'Array.Transposed 'Sẽ chính xác hơn và làm cho lập trình viên rõ ràng hơn.
Khi làm việc với phương thức 'Array.Transpose ()', người ta có thể vô tình thử sử dụng mã như sau:
Array myArray = new Array();
myArray.Transpose();
Nhưng nếu phương thức 'Transpose' trả về một mảng mới mà không ảnh hưởng đến đối tượng được tham chiếu, thì mã này không làm gì cả - nghĩa là, 'myArray' sẽ lặng lẽ không bị chuyển đổi. (Tôi cho rằng nếu 'Transpose' là một thuộc tính, thì trình biên dịch sẽ hiểu rằng phần trên không hợp pháp, nhưng hướng dẫn của FxCop nói rằng một thành viên thực hiện chuyển đổi phải là một phương thức.)
Nhưng nếu phương thức được đặt tên ở thì quá khứ là 'Array.Transposed', thì người dùng sẽ rõ ràng hơn rằng cú pháp sau là bắt buộc:
Array myArray = new Array();
Array transposedArray = myArray.Transposed();
Các tên khác mà tôi nghĩ sẽ phù hợp với danh mục này sẽ là các thành viên có tên 'Thay đổi kích thước' so với 'Thay đổi kích thước', 'Chuyển đổi' so với 'Chuyển đổi', v.v ... thì hiện tại sẽ được sử dụng cho các thành viên ảnh hưởng đến đối tượng được tham chiếu, trong khi thì quá khứ sẽ được sử dụng cho các thành viên trả về giá trị mới mà không ảnh hưởng đến đối tượng được tham chiếu.
Một cách tiếp cận phổ biến hơn hiện nay là tiền tố mỗi tên bằng "Nhận" hoặc "Tới", nhưng tôi nghĩ rằng điều này làm tăng thêm trọng lượng không cần thiết, trong khi thay đổi sang thì quá khứ truyền đạt ý nghĩa một cách hiệu quả.
Điều này có ý nghĩa với các lập trình viên khác ở đây, hay ý tưởng căng thẳng trong quá khứ này nghe có vẻ quá vụng về khi đọc nó?
Biên tập:
Những cuộc thảo luận tuyệt vời dưới đây, tôi cảm ơn mọi người rất nhiều. Một vài điểm tôi muốn tóm tắt dựa trên ý kiến của bạn và suy nghĩ sửa đổi của riêng tôi về điều này sau đây.
Phương pháp Chaining "Fluent" Cú pháp
Dựa trên các cuộc thảo luận dưới đây, việc sử dụng thì quá khứ có lẽ có giá trị khi được sử dụng trên một lớp có thể thay đổi để làm rõ các thành viên nào làm hoặc không làm ảnh hưởng đến trạng thái bên trong của đối tượng được tham chiếu.
Tuy nhiên, đối với các lớp bất biến, phần lớn các trường hợp (người ta hy vọng), tôi nghĩ rằng việc sử dụng thì quá khứ có thể làm cho cú pháp trở nên khó xử một cách không cần thiết.
Ví dụ, với "cú pháp trôi chảy", chẳng hạn như những cú pháp được tạo bởi chuỗi phương thức, việc sử dụng thì quá khứ sẽ làm cho mã ít đọc hơn. Ví dụ: khi sử dụng LINQ qua C #, một chuỗi phương thức điển hình có thể trông như sau:
dataSource.Sort().Take(10).Select(x => x.ToString);
Nếu thay đổi thành thì quá khứ, điều này sẽ trở nên khó xử:
dataSource.Sorted().Taken(10).Selected(x => x.ToString);
Hãy nhớ rằng, dataSource.Sort () thực sự có ý nghĩa rõ ràng hơn dataSource.Sort (), vì các biểu thức LINQ luôn tạo ra một phép liệt kê mới mà không ảnh hưởng đến nguồn. Tuy nhiên, vì chúng tôi hoàn toàn nhận thức được điều này khi sử dụng mô hình này, việc sử dụng thì quá khứ là dư thừa và làm cho "sự trôi chảy" của việc đọc nó trở nên khó xử vì không có lợi ích thực sự.
Sử dụng các thuộc tính so với các phương thức
Một vấn đề chính được đưa ra dưới đây liên quan đến các nguyên tắc của FxCop về việc sử dụng các phương thức "Nhận" so với các thuộc tính chỉ đọc. Ví dụ: quy tắc FxCop CA1024 .
Mặc dù không được đề cập rõ ràng trong quy tắc FxCop đó, việc sử dụng các phương thức "To" dường như cũng sẽ áp dụng cho lý do này, vì các phương thức ToXXXXXX () là các phương thức chuyển đổi. Và trong trường hợp ToArray (), phương thức vừa là phương thức chuyển đổi vừa là phương thức trả về một mảng.
Sử dụng thì quá khứ cho các thuộc tính Boolean
Một số gợi ý rằng thì quá khứ có thể bao hàm một giá trị boolean, ví dụ: thuộc tính 'Thành công' hoặc 'Đã kết nối'. Tôi tin rằng các câu trả lời bên dưới nhấn mạnh việc sử dụng 'Is', 'Has' hoặc 'Are' cho các thuộc tính và trường Boolean là chính xác. Thì quá khứ cũng có thể giúp về vấn đề này, nhưng gần như không bằng cách sử dụng tiền tố 'Is'. Vui lòng sử dụng thì quá khứ cho các thuộc tính và trường Boolean, điều đó có ích, nhưng tôi nghĩ rằng việc đặt tiền tố tên với 'Is', 'Has' hoặc 'Are' thậm chí còn quan trọng hơn.
Kết luận chung?
Đối với vấn đề Tranpose () so với Transposed (), tôi nghĩ rằng 'skizzy' đã hiểu đúng, cho rằng đó phải là Transpose () cho một hành động đột biến so với GetTransposed () cho kết quả không đột biến. Điều này làm cho nó rõ ràng 100%. Nhưng, một lần nữa, tôi nghĩ rằng điều này chỉ có thể áp dụng cho một lớp có thể thay đổi, chẳng hạn như một mảng.
Đối với các lớp không thay đổi, đặc biệt là khi có thể sử dụng cú pháp chuỗi phương thức trôi chảy, thì tôi nghĩ rằng cú pháp này sẽ trở nên khó xử không cần thiết. Ví dụ: so sánh:
var v = myObject.Transpose().Resize(3,5).Shift(2);
đến:
var v = myObject.GetTransposed().GetResized(3,5).GetShifted(2);
Hmmm ... thực sự, ngay cả ở đây dường như làm rõ 100% rằng kết quả không ảnh hưởng đến nguồn, nhưng tôi không chắc chắn.
Tôi đoán đối với một mô hình như LINQ nơi nó được biết đến, việc sử dụng "Nhận" và / hoặc thì quá khứ là không cần thiết, nhưng đối với một API mới, ban đầu nó có thể có một số giá trị! Nếu API chỉ chứa các đối tượng không thay đổi, một khi người dùng hiểu điều này, việc sử dụng "Nhận" và / hoặc thì quá khứ chỉ làm giảm khả năng đọc.
Vì vậy, tôi nghĩ rằng không có câu trả lời dễ dàng ở đây. Tôi đoán người ta cần suy nghĩ về toàn bộ API của bạn và chọn cẩn thận!
- Mike