C # - Tại sao các tiền tố trên các trường không được khuyến khích?


19

Quay lại thời xưa, chúng tôi đã làm ký hiệu Hungary. Bây giờ được coi là passé và đối với hầu hết các phần tôi không sử dụng nữa, nhưng tôi vẫn thấy sử dụng m_tiền tố để chỉ ra các trường thành viên.

Đối với tôi, nếu tôi đang đọc qua mã của người khác và tôi thấy điều này:

count = 3;

Tôi giả sử rằng đó countlà một biến cục bộ của hàm đó và tôi đang làm một cái gì đó sẽ được sử dụng ở nơi khác trong hàm; nếu tôi thấy điều này:

m_count = 3;

Tôi ngay lập tức nhận ra rằng tôi đang cập nhật trạng thái của đối tượng.

Các nguyên tắc phong cách của Microsoft nói rằng đó là cách làm sai. Tôi phải đặt tên cho các trường không công khai của mình chính xác như các biến tạm thời được xác định trong hàm. Không m_, thậm chí không phải là một dấu gạch dưới đơn giản.

Vâng, chúng ta có thể định nghĩa phong cách mã hóa của riêng mình, nhưng sau đó tôi phải vật lộn với nhiều công cụ phân tích mã tĩnh khác nhau, để thuyết phục họ rằng cách làm việc của chúng tôi là ổn.

Tôi rất vui khi thay đổi phong cách của Microsoft, nhưng tôi muốn biết tại sao mọi thứ lại như vậy.

Tại sao bây giờ nó được coi là xấu để có thể biết liệu một biến là hàm cục bộ hay thành viên?

PS Điều này rất giống với các thực tiễn tốt nhất hiện tại được coi là liên quan đến từ khóa của điều này trên mạng và các phương thức trong c # là gì? , nhưng tôi hỏi về m_khôngthis.

PPS Cũng xem Tại sao Microsoft tạo tham số, biến cục bộ và trường riêng có cùng quy ước đặt tên?


9
C # không có thistừ khóa? Bạn không thể tham khảo các thành viên sử dụng this, chẳng hạn như this.count?
Thất

3
Tiền tố m_ là C ++ - ism nơi nó tránh các xung đột tên giữa các trường và phương thức. Trong C #, đây không phải là vấn đề vì tên phương thức phải bắt đầu bằng chữ hoa, trường có chữ thường.
amon

4
Nếu bạn đang in mã vào năm 2017, bạn đang làm sai điều gì đó. Trong hai kịch bản khác, điều khá rõ ràng là countkhông xuất hiện từ đâu vì nó không được khai báo trong phương thức. Thành thật mà nói, đối số "ngoài IDE" thực sự yếu. Đặc biệt là vì thậm chí có các công cụ đánh giá mã hoạt động trong IDE.
Andy

4
Vẫn có bài viết liên quan từ Joel .
Kasey speakman

Câu trả lời:


19

Khi họ đang làm việc trên API cho Windows, Microsoft đã khuyến nghị sử dụng Ký hiệu Hungary, sử dụng 'm_', cũng như 'i', 'sz', v.v. Vào thời điểm đó, điều này rất hữu ích vì IDE không mạnh mẽ đủ để hiển thị thông tin này cho bạn

C #, mặt khác, có một IDE rất mạnh ngay từ đầu.

Vì vậy, họ đã đưa ra khuyến nghị trong Nguyên tắc đặt tên của Microsoft cho C # cho các trường tĩnh hoặc được bảo vệ công khai:

 DO use PascalCasing in field names.
 DO name fields using a noun, noun phrase, or adjective.
X DO NOT use a prefix for field names.

Giờ đây, khi bạn có thể di chuột qua chuột hoặc nhấn CTRL + K + W và nhận tất cả thông tin về thành viên, Microsoft đã xác định rằng tiền tố có dạng xấu; chúng là một giải pháp thủ công cho một vấn đề đã được giải quyết.

Các trường riêng được loại trừ cụ thể khỏi hướng dẫn, nhưng Microsoft dường như đã đi đến kết luận rằng đây là trường hợp ngay cả đối với các trường riêng đi về phía trước, bạn có thể thấy nếu bạn trỏ Resharper tại .NET 4.5 hoặc .NET Core.

Sử dụng các công cụ của bạn, không làm điều đó bằng tay.


2
Câu trả lời tương tự với Andy ... có nhưng ... có nhiều tình huống tôi đang xem mã bên ngoài IDE. Ví dụ - (1) công cụ hợp nhất. (2) công cụ xem xét mã. (3) (thở hổn hển) bản in.
Betty Crokker

Andy đã đăng theo đúng nghĩa đen ngay lập tức tôi đã làm. Tôi thấy "1 bình luận mới" bật lên khi tôi nhấp vào "thêm câu trả lời". Theo như những công cụ đó, hai trong số chúng đã có trong IDE. Bản in ... tại sao bạn làm điều đó?
Kevin Phí

1
Câu hỏi ban đầu của tôi vẫn chưa được trả lời ... vâng, Microsoft cho biết không sử dụng m_ và các nhà sản xuất công cụ tuân theo điều đó, nhưng đó không phải là lý do kỹ thuật để sử dụng m_, đó thường được gọi là "kháng cáo lên chính quyền". Lý do kỹ thuật duy nhất tôi thấy không sử dụng m_ đến từ Timothy Truckle và tôi không hiểu điều đó ...
Betty Crokker

8
@BettyCrokker Vì m_ thêm hoàn toàn không có giá trị. IDE cho bạn biết thành viên hay không, vì vậy m_ là dư thừa. Bất kỳ lý do tại sao bạn cố định trên m_? Tại sao không l_ (cho địa phương)? Tại sao không afsdfjdskfjas_? Tôi sẽ hạ bệ câu hỏi, vì dù sao đó cũng là một cuộc tranh luận tôn giáo ngớ ngẩn. Làm bất cứ điều gì bạn muốn. Các nguyên tắc bạn đang gõ cũng nói "Các nguyên tắc đặt tên trường áp dụng cho các trường công khai và được bảo vệ tĩnh . Các trường nội bộ và riêng tư được _not_ bao phủ bởi các hướng dẫn và các trường đối tượng công khai hoặc được bảo vệ không được phép theo hướng dẫn thiết kế thành viên."
Andy

1
@BettyCrokker OK, nhưng bạn đang hỏi về các nguyên tắc được thực hiện với giả định đó. Bạn cũng đang phàn nàn về các công cụ tĩnh cũng có khả năng sử dụng giả định đó, bởi vì "không ai" (trong phạm vi sai số thống kê có thể chấp nhận được) in ra mã C # của họ. Tôi không biết bạn sử dụng công cụ phân tích thống kê nào, nhưng Resharper khá cụ thể: Các trường riêng là "_lowerCase". Các thành viên công cộng thuộc bất kỳ loại nào hoặc "UpperCase" và người dân địa phương là "lowCase". Dù sao, tiết kiệm trên "m" thực sự trông khá đẹp.
Kevin Phí

17

C # không có bất kỳ biến toàn cục nào, do đó chỉ để lại các biến cục bộ và trường lớp.

Và nếu bạn có quá nhiều biến cục bộ, bạn sẽ không biết liệu định danh có phải là một biến hay không, bạn chắc chắn đã vi phạm một trong những nguyên tắc để quản lý sự phức tạp một cách đáng tiếc nhất.

Cố gắng trích xuất một đối tượng tham số, cố gắng phân chia chức năng của bạn thành nhiều đối tượng đơn giản hơn, bạn chắc chắn nên cấu trúc lại mã của mình trừ khi bạn thích chìm đắm trong những chi tiết vụn vặt và phức tạp, cũng như không liên quan đến khả năng bảo trì.

Bây giờ chúng tôi đã xác định rằng mục đích của "điều này là một thành viên" không còn tồn tại vì phạm vi chức năng nên quá nhỏ và phạm vi toàn cầu không tồn tại, có một nhược điểm đối với những điểm đánh dấu đó: Chúng ức chế di chuyển đối số / biến cục bộ cho các thành viên, hoặc ngược lại.


Khi bạn chấm vào nó, nó cũng có thể là một lớp hoặc không gian tên.
CodeInChaos

3
Tôi không nghĩ rằng điều này thực sự trả lời câu hỏi.
Vladimir Stokic

5
@FrankHileman Thật ra là vậy. Nó giải thích tại sao không có lý do chính đáng cho việc làm xấu tên.
Ded repeatator

2
"Xấu xí"? Nếu đây là trường hợp, nó là một câu hỏi chỉ có ý kiến. Mọi người có thể có một quan điểm khác nhau về sự xấu xí. Có nhiều lý do để thích một quy ước hơn một quy ước khác, nhưng không có quy ước chuẩn trong trường hợp này.
Frank Hileman

1
@Ded repeatator vẻ đẹp là trong mắt của kẻ si tình. Những quy ước tôi từng coi là xấu xí, bây giờ tôi đánh giá cao là hữu ích.
Frank Hileman

11

Tại sao các nhà phát triển tránh chuẩn bị không gian tên với lệnh sử dụng không gian tên?

System.DateTime()rõ ràng hơn nhiều DateTime(). Nó cho tôi biết chính xác những gì tôi đang giải quyết. Có phải chỉ vì chúng ta lười đánh máy?

Không. Chúng tôi là những người đánh máy lười biếng, nhưng đó không phải là lý do.

Chúng tôi thích các kiểu mã hóa cho phép chúng tôi bỏ qua chi tiết và tập trung vào trừu tượng. Buộc các tên để truyền đạt chi tiết cấu trúc là mất tập trung. Khi tôi làm việc với một thuật toán phức tạp, tôi không muốn những cái tên cứ khăng khăng nhắc nhở tôi từng chi tiết nhỏ về thứ tôi đang làm việc. Tôi chỉ cần tên để giữ cho tôi khỏi nhầm lẫn TimerDateTime. Tôi sẽ lo lắng nếu những thứ đó tương thích ở một nơi khác.

Đó là cùng một lý do bạn không muốn hai người trong nhóm của bạn tên là Jon. Việc họ có họ không phải là lý do để cung cấp cho họ tiền tố hoặc hậu tố. Tôi sẽ gọi bạn là Skeet. Bất cứ điều gì nhiều hơn là một nỗi đau bằng phẳng.


2
Điều này dường như không trả lời câu hỏi. Không có ưu tiên chung hoặc quy ước cho các lĩnh vực riêng tư trong .net.
Frank Hileman

12
@FrankHileman Nói chung, chúng tôi thích những cái tên hay. Các quy ước không tạo ra tên tốt. Các quy ước tạo ra các tên như McOhPlease Von StopItAlperedStine.
candied_orange

Các quy ước chỉ là để làm việc dễ dàng hơn với mã của các nhà phát triển khác nhau. Câu trả lời của bạn không đề cập đến trường đại học, nhưng không có quy ước cho các lĩnh vực riêng tư, vì vậy câu hỏi dựa trên giả định sai.
Frank Hileman

7

Hãy mở rộng một chút.

Có 3 kiểu tiền tố phổ biến, tất cả các kiểu đôi khi gặp trong mã c #:

  • m_
  • _
  • điều này.

Các tiền tố như vậy thường được sử dụng trong việc thực hiện riêng của một lớp . Đề xuất của Microsoft chủ yếu là về các phần tiếp xúc của một lớp.

Ưu điểm của việc sử dụng m_hơn _là các tiền tố có thể giống nhau trong toàn bộ codebase của bạn nếu bạn sử dụng c # cũng như ngôn ngữ mà sử dụng _như một tiền tố là không được phép . * Ưu điểm của việc m_trên this.là nó ngắn hơn và rằng bạn sẽ không vô tình quên đi tiền tố.

Ưu điểm của _hơn m_là nó ngắn hơn và mọi thứ bắt đầu bằng tiền tố được sắp xếp ở trên cùng được sắp xếp theo thứ tự abc bằng một công cụ. Ưu điểm của việc _trên this.là nó ngắn hơn và rằng bạn sẽ không vô tình quên đi những tiền tố.

Ưu điểm của this.hơn m__là bạn có thể sử dụng nó trong một cơ sở mã trong đó _hoặc m_không phải là một quy ước phổ biến và được chấp nhận. Điều đó cũng có nghĩa là không ai cần biết về quy ước _hoặc m_quy ước, có thể được coi là làm cho mọi thứ đơn giản hơn. Như một nhược điểm, bởi vì trình biên dịch không quan tâm đến tiền tố này, this.đôi khi tiền tố sẽ bị thiếu và do đó không đáng tin cậy như một chỉ báo.


* Khi bạn bắt đầu truy cập các lớp C # sử dụng _từ C ++ / CLI (thực sự không nên sử dụng _), bạn sẽ nhận thấy rằng việc đồng ý với một tiền tố phổ biến phức tạp hơn mức cần thiết. Quyết định không có tiền tố được loại bỏ tiếng ồn đó. Kết hợp câu trả lời này với câu trả lời của Dedsplator, mà tôi sẽ diễn giải là "lợi thế của tiền tố gần như không đáng kể" và nó cho chúng ta: "Có một vấn đề nhỏ khi sử dụng tiền tố và một nhược điểm nhỏ, do đó, nó không phải là một lựa chọn hợp lệ sử dụng chúng".


một câu hỏi cũ hơn về stackoverflow liên quan đến điều này.


1
So sánh tốt đẹp. Tuy nhiên, tôi thấy rằng không sử dụng bất kỳ tiền tố nào hoạt động tốt trong thực tế.
Phil1970

6

Cần lưu ý rằng hướng dẫn kiểu MS chỉ nói về các phương thức và biến công khai và được bảo vệ. tức là những nhà phát triển khác sẽ xem nếu họ sử dụng thư viện của bạn.

Ý tưởng là các thư viện của Microsoft được cung cấp giao diện chuẩn cho các nhà phát triển tiêu thụ chúng.

Bạn có thể tự do sử dụng bất kỳ phong cách nào bạn thích trên các biến riêng tư hoặc cục bộ của bạn.

Đã nói rằng các tiền tố biến đổi nói chung không được khuyến khích vì một số lý do

  • Họ có thể sai, và do đó gây hiểu lầm
  • Nếu bạn đang thêm tiền tố theo loại biến thì không rõ bạn xử lý các lớp mà bạn đã tạo như thế nào.
  • Có một số quy ước và họ không luôn đồng ý. Những gì bạn thấy hữu ích một nhà phát triển khác có thể tìm thấy không có ích
  • Trong trường hợp các biến thành viên, bạn có thể sử dụng 'cái này'. từ khóa để chỉ ra phạm vi và trình biên dịch sẽ thực thi nó.

2
Ban đầu tôi không sử dụng tiền tố nào cho các trường. Sau đó, tôi chuyển sang sử dụng một ký tự "_", vì tôi thấy những người khác sử dụng nó bởi vì nó di chuyển tất cả các trường lên đầu danh sách thành viên được sắp xếp theo thứ tự chữ cái khi bạn sử dụng hộp danh sách thả xuống IDE. Việc thiếu một quy ước chuẩn có thể gây khó chịu khi đọc mã được viết bởi nhiều nhà phát triển khác nhau.
Frank Hileman

Sau một thời gian, bạn thấy rất nhiều phong cách khác nhau, bạn chỉ cần bỏ qua chúng. Nếu bạn cố gắng thực thi một phong cách, bạn sẽ liên tục tái cấu trúc mọi thứ
Ewan

4
Nếu bạn áp dụng "Chúng có thể sai và do đó gây hiểu lầm" cho hầu hết mọi thứ, bạn sẽ nhanh chóng phát hiện ra rằng bạn không nên đặt tên biến hoặc hàm - rốt cuộc chúng có thể sai! Và tôi đoán rằng điểm đạn thứ hai của bạn có nghĩa vụ phải nói "các lớp mà bạn chưa tạo ra"? Mặt khác, tôi không hiểu điều đó ... Trong mọi trường hợp, nó bắt đầu có vẻ như có một tiền tố gạch dưới duy nhất cho các trường ngoài công lập là một tiêu chuẩn không chính thức, đó có lẽ là hướng chúng ta sẽ đi.
Betty Crokker

một số thứ được trình biên dịch kiểm tra, vì vậy m_count có thể không phải là biến thành viên, nhưng this.count sẽ luôn là
Ewan

sử dụng rất nhiều ppl _ nhưng mọi thứ thay đổi theo thời gian, bạn sẽ thấy rằng mã được viết để 'thực hành tốt nhất' năm ngoái không khớp với quy ước năm nay
Ewan

4

Đối với tôi, nếu tôi đang đọc qua mã của người khác và tôi thấy điều này:

count = 3;

Tôi giả sử rằng 'Count' là một biến cục bộ của hàm đó và tôi đang làm một cái gì đó sẽ được sử dụng ở nơi khác trong hàm

Và bạn sẽ hoàn toàn đúng nếu bạn đang đọc mã nguồn tôn trọng các quy ước về phong cách của C #. Trong mã như vậy:

this.count = 3;

gán giá trị cho một trường.

count = 3;

gán một giá trị cho một biến cục bộ.

Do đó, các quy ước về phong cách của C # rất rõ ràng và không mơ hồ. Họ buộc bạn không sử dụng bất kỳ tiền tố nào đơn giản chỉ vì bạn không cần.

Đối với các mã nguồn mà các tác giả đã quyết định sử dụng công ước cá nhân của họ thay vào đó, bạn nên yêu cầu họ cá nhân tại sao họ lại tạo ra một sự lựa chọn để làm như vậy. Nếu họ không sử dụng các tiền tố như dấu gạch dưới, trong khi không sử dụng this., điều đó sẽ dẫn đến hiệu quả không chỉ khó đọc mã, mà cả các trường hợp cần một quy ước bổ sung:

public class Hello
{
    private string greetings;

    public Hello(string greetings)
    {
        greetings = greetings; // Wait, what is that?!
    }
}

Không C # có từ khóa này? Bạn không thể tham khảo các thành viên sử dụng cái này, chẳng hạn như this.count?

Có, nhưng (1) nó gõ nhiều hơn và (2) thật dễ quên. Nếu trường được đặt tên là m_count, tôi không phải nhớ nhập this.m_count

Ở đây, tuy nhiên, bạn đã sai.

Nó gõ nhiều hơn khi bạn viết mã của mình trong Notepad. Với một IDE có tự động hoàn thành hoặc tốt hơn là IntelliSense, việc so sánh giữa this.countm_countkhông rõ ràng. Lưu ý Shift+ -bắt buộc để nhập dấu gạch dưới.

Đối với những người dễ quên, một lần nữa, điều này chỉ phù hợp với người dùng Notepad. Không chỉ StyleCop và Resharper sẽ không cho phép bạn quên đặt this.khi cần, mà sau vài giờ lập trình, đặt this.khi cần trở thành thói quen.


6
Tôi thấy rằng thischỉ sử dụng khi bạn cần nó dẫn đến một cảm giác thực sự không nhất quán và làm tôi mất tập trung quá thường xuyên. Nếu bạn sẽ sử dụng thisthay vì tiền tố, tôi tin rằng bạn nên luôn luôn sử dụng nó. Trong trường hợp đó, nó trở thành tiền tố và bạn cũng có thể sử dụng _.
RubberDuck

1
RubberDuck đã đúng. "điều này." là một tiền tố, mặc dù, nó có ý nghĩa trình biên dịch.
Frank Hileman

4

Tiền tố "thành viên" là một loại chi tiết thực hiện. Nó đánh lạc hướng sự chú ý của bạn từ miền vấn đề sang miền giải pháp kỹ thuật làm thiên lệch tâm trí của bạn khi nghĩ đến các phép tái cấu trúc có thể. - tôi

bạn có thể giải thích thêm? Của bạn là lý do duy nhất tôi thấy tại sao không sử dụng tiền tố và tôi không hiểu nó ... (ý tôi là, những điều khác mà mọi người đang nói là lý do tại sao tôi không phải sử dụng nó, không giống với lý do tại sao tôi không nên) - Betty Crokker

Quan điểm của tôi là mở rộng câu trả lời của @CandiedOrange và @Ewan.

Tiền tố làm cho việc tái cấu trúc khó hơn

Khi mã của bạn phát triển các biến và phương thức có thể thay đổi phạm vi của chúng. Ví dụ. bạn có thể tạo một phương thức riêng tư và sau đó phát hiện ra rằng nó cũng có sẵn cho các lớp (mới) khác. Tương tự có thể xảy ra với các tham số phương thức và các biến cục bộ.

Giả sử bạn tạo một máy tính Thuế. Theo nguyên tắc phạm vi hiển thị cho thuê đối với các biến bạn bắt đầu bằng một phương thức lấy cả hai, thuế suấtgiá trị cơ sở làm tham số:
(ví dụ có thể trông giống Java-ish ...)

class TaxCalculator{
   double Calculate(double p_TaxRateInpercent, double p_BaseValue){
     return (100+p_TaxRateInpercent)/100 * p_BaseValue;
   }
} 

tiếp theo bạn phải thực hiện thao tác ngược lại và theo TDD, bạn thực hiện nó với ít nỗ lực nhất:

class TaxCalculator{
   double Calculate(double p_TaxRateInpercent, double p_BaseValue){
     return (100+p_TaxRateInpercent)/100 * p_BaseValue;
   }
   double CalculateBase(double p_TaxRateInpercent, double p_TaxedValue){
     return p_TaxedValue/((100+p_TaxRateInpercent)/100);
   }
} 

Tiếp theo TDD muốn bạn cấu trúc lại mã để trở nên sạch hơn, đó là giảm danh sách tham số của cả hai phương thức.
(Vâng, bạn sẽ trích xuất phép tính nhân đôi trước, nhưng hãy để tôi lấy điểm của tôi ...)
Giải pháp rõ ràng là thay đổi thuế suất thành một biến thành viên bằng cách chuyển nó dưới dạng tham số hàm tạo.

class TaxCalculator{
   double m_TaxRateInpercent;
   TaxCalculator(double p_TaxRateInpercent){
     m_TaxRateInpercent = p_TaxRateInpercent;
   }
   double Calculate(double p_BaseValue){
     return (100+m_TaxRateInpercent)/100 * p_BaseValue;
   }
   double CalculateBase(double p_TaxedValue){
     return p_TaxedValue/((100+m_TaxRateInpercent)/100);
   }
} 

Như bạn có thể thấy, chúng tôi đã phải thay đổi tất cả các dòng phương thức hiện có của chúng tôi (bất kỳ dòng nào chúng tôi sử dụng p_TaxRateInpercentlà chính xác.

Vấn đề là, bạn không có sự hỗ trợ nào từ IDE của mình để thực hiện việc đổi tên trong toàn lớp. Việc duy nhất giúp nó tìm kiếm / thay thế cũng sẽ thay đổi hàm tạo hoặc bất kỳ phần nào vô tình chứa chuỗi p_TaxRateInpercent.
IDE của bạn có thể cung cấp một thay đổi để ... tái cấu trúc cho các tên biến không xác định nhưng điều này có thể bị giới hạn trong phạm vi của phương thức

Không có tiền tố, chữ ký của phương thức sẽ thay đổi. Không cần đổi tên là cần thiết cả.


Tiền tố làm lộn xộn lịch sử SCM khi thay đổi

Ngoài ra, SCM ghi lại sự thay đổi của tiền tố là những thay đổi trong logic mặc dù logic không thay đổi! Lịch sử SCM lộn xộn với thay đổi kỹ thuật này ẩn giấu những gì quan trọng và tăng nguy cơ xung đột với những thay đổi (logic thực) của người khác.


1

Tôi sử dụng tiền tố _ cho tất cả các biến thành viên. Tôi ghét tiền tố 'này' bởi vì, trong khi một số người cho rằng đó là cách làm đúng đắn - nó gây ra nhiều tiếng ồn / lộn xộn cho cơ sở mã của bạn. Một dấu gạch dưới duy nhất cũng là một thông lệ phổ biến trong các mẫu của Microsoft.

Vì vậy, trong ví dụ của bạn, tôi có:

int _count = 10;
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.