Là #regions một antipotype hoặc mùi mã?


265

C # cho phép sử dụng #region/ #endregiontừ khóa để làm cho các vùng mã có thể thu gọn trong trình chỉnh sửa. Bất cứ khi nào tôi làm điều này mặc dù tôi làm điều đó để ẩn các đoạn mã lớn có thể được tái cấu trúc thành các lớp hoặc phương thức khác. Ví dụ, tôi đã thấy các phương thức chứa 500 dòng mã với 3 hoặc 4 vùng chỉ để làm cho nó có thể quản lý được.

Vì vậy, việc sử dụng hợp lý các khu vực là một dấu hiệu của rắc rối? Nó dường như là như vậy với tôi.


9
FYI: CodeMap loại bỏ khá nhiều nhu cầu cho các khu vực. visualstudiogallery.msdn.microsoft.com/ Kẻ - Nhấp và nó sẽ đưa bạn đến phương thức / thuộc tính / bất cứ điều gì. Tôi sử dụng nó mỗi ngày và thật tuyệt vời khi bạn đạt được năng suất và cả về mặt nhận thức. Bạn có được một "tầm nhìn chim" rõ ràng hơn nhiều về lớp học.

7
Bất cứ ai cũng có thể làm cho nó một wiki? Không có câu trả lời đúng hay sai cho câu hỏi này (tốt, trong lý do), nó gần như hoàn toàn chủ quan.
Ed S.

6
Đối với những gì nó có giá trị, Jeff Atwood ghét họ . Ông lập luận rằng họ che giấu mã xấu.
Brian

3
Mùi mã là một nhà phát triển không tắm và không sử dụng chất khử mùi!
marko

5
Các khu vực được chế tạo cẩn thận trong mã hôi thối là những gì một vài vắt của Febreeze làm trên một chiếc ghế bành. Nó làm cho nó có thể chịu được cho đến khi bạn tìm thấy tiền (thời gian) để thay thế nó.
Newtopian

Câu trả lời:


285

Mùi mã là một triệu chứng chỉ ra rằng có một vấn đề trong thiết kế sẽ có khả năng làm tăng số lượng lỗi: đây không phải là trường hợp đối với các vùng, nhưng các vùng có thể góp phần tạo ra mùi mã, như các phương thức dài.

Từ:

Một mô hình chống (hoặc phản mẫu) là một mô hình được sử dụng trong các hoạt động xã hội hoặc kinh doanh hoặc công nghệ phần mềm có thể được sử dụng phổ biến nhưng không hiệu quả và / hoặc phản tác dụng trong thực tế

khu vực chống mẫu. Họ yêu cầu nhiều công việc hơn mà không làm tăng chất lượng hoặc khả năng đọc mã, điều này không làm giảm số lượng lỗi và điều này chỉ có thể làm cho mã phức tạp hơn để tái cấu trúc.

Không sử dụng các vùng bên trong các phương thức; thay thế

Phương pháp phải ngắn gọn . Nếu chỉ có mười dòng trong một phương thức, có lẽ bạn sẽ không sử dụng các vùng để ẩn năm trong số chúng khi làm việc trên năm dòng khác.

Ngoài ra, mỗi phương pháp phải làm một và một điều duy nhất . Các khu vực, mặt khác, được dự định để phân tách những thứ khác nhau . Nếu phương thức của bạn thực hiện A, thì B, sẽ hợp lý khi tạo hai vùng, nhưng đây là một cách tiếp cận sai; thay vào đó, bạn nên cấu trúc lại phương thức thành hai phương thức riêng biệt.

Sử dụng các vùng trong trường hợp này cũng có thể làm cho việc tái cấu trúc trở nên khó khăn hơn. Hãy tưởng tượng bạn có:

private void DoSomething()
{
    var data = LoadData();
    #region Work with database
    var verification = VerifySomething();
    if (!verification)
    {
        throw new DataCorruptedException();
    }

    Do(data);
    DoSomethingElse(data);
    #endregion

    #region Audit
    var auditEngine = InitializeAuditEngine();
    auditEngine.Submit(data);
    #endregion
}

Thu gọn khu vực đầu tiên để tập trung vào khu vực thứ hai không chỉ có rủi ro: chúng ta có thể dễ dàng quên đi ngoại lệ ngăn chặn dòng chảy (có thể có một điều khoản bảo vệ với một returnthay thế, thậm chí còn khó phát hiện hơn), nhưng cũng có vấn đề nếu mã được tái cấu trúc theo cách này:

private void DoSomething()
{
    var data = LoadData();
    #region Work with database
    var verification = VerifySomething();
    var info = DoSomethingElse(data);

    if (verification)
    {
        Do(data);
    }

    #endregion

    #region Audit
    var auditEngine = InitializeAuditEngine(info);
    auditEngine.Submit(
        verification ? new AcceptedDataAudit(data) : new CorruptedDataAudit(data));
    #endregion
}

Bây giờ, các khu vực không có ý nghĩa và bạn không thể đọc và hiểu mã trong khu vực thứ hai mà không cần nhìn vào mã trong khu vực đầu tiên.

Một trường hợp khác đôi khi tôi thấy là trường hợp này:

public void DoSomething(string a, int b)
{
    #region Validation of arguments
    if (a == null)
    {
        throw new ArgumentNullException("a");
    }

    if (b <= 0)
    {
        throw new ArgumentOutOfScopeException("b", ...);
    }
    #endregion

    #region Do real work
    ...
    #endregion
}

Thật hấp dẫn khi sử dụng các vùng khi xác thực đối số bắt đầu trải rộng hàng chục LỘC, nhưng có một cách tốt hơn để giải quyết vấn đề này: đó là cách được sử dụng bởi mã nguồn .NET Framework:

public void DoSomething(string a, int b)
{
    if (a == null)
    {
        throw new ArgumentNullException("a");
    }

    if (b <= 0)
    {
        throw new ArgumentOutOfScopeException("b", ...);
    }

    InternalDoSomething(a, b);
}

private void InternalDoSomething(string a, int b)
{
    ...
}

Không sử dụng các phương thức bên ngoài để nhóm

  • Một số người sử dụng chúng để nhóm các trường, thuộc tính, v.v ... Cách tiếp cận này sai: nếu mã của bạn tuân thủ StyleCop, thì các trường, thuộc tính, phương thức riêng, hàm tạo, v.v ... đã được nhóm lại với nhau và dễ tìm. Nếu không, đã đến lúc bắt đầu suy nghĩ về việc áp dụng các quy tắc đảm bảo tính đồng nhất trên cơ sở mã của bạn.

  • Những người khác sử dụng các khu vực để ẩn rất nhiều thực thể tương tự . Ví dụ: khi bạn có một lớp với hàng trăm trường (tạo ra ít nhất 500 dòng mã nếu bạn đếm các bình luận và khoảng trắng), bạn có thể bị cám dỗ đặt các trường đó vào một vùng, thu gọn nó và quên chúng đi. Một lần nữa, bạn đang làm sai: với rất nhiều trường trong một lớp, bạn nên nghĩ tốt hơn về việc sử dụng tính kế thừa hoặc cắt đối tượng thành nhiều đối tượng.

  • Cuối cùng, một số người bị cám dỗ sử dụng các vùng để nhóm các thứ liên quan lại với nhau : một sự kiện với đại biểu của nó hoặc một phương thức liên quan đến IO với các phương thức khác liên quan đến IO, v.v. Trong trường hợp đầu tiên, nó trở thành một mớ hỗn độn rất khó duy trì , đọc và hiểu. Trong trường hợp thứ hai, thiết kế tốt hơn có lẽ sẽ tạo ra một vài lớp.

Có sử dụng tốt cho các khu vực?

Không. Có một cách sử dụng kế thừa: mã được tạo. Tuy nhiên, các công cụ tạo mã chỉ phải sử dụng các lớp một phần thay thế. Nếu C # có các vùng hỗ trợ, thì chủ yếu là vì sử dụng di sản này và vì hiện tại có quá nhiều người đã sử dụng các vùng trong mã của họ, nên không thể xóa chúng mà không phá vỡ các cơ sở mã hiện có.

Hãy suy nghĩ về nó như là về goto. Thực tế là ngôn ngữ hoặc IDE hỗ trợ một tính năng không có nghĩa là nó nên được sử dụng hàng ngày. Quy tắc StyleCop SA1124 rất rõ ràng: bạn không nên sử dụng các vùng. Không bao giờ.

Ví dụ

Tôi hiện đang thực hiện đánh giá mã về mã đồng nghiệp của mình. Các cơ sở mã chứa rất nhiều vùng và thực sự là một ví dụ hoàn hảo về cả cách không sử dụng các vùng và tại sao các vùng dẫn đến mã xấu. Dưới đây là một số ví dụ:

Quái vật 4.000 LỘC:

Gần đây tôi đã đọc ở đâu đó trên Lập trình viên. Khi một tệp chứa quá nhiều usings (sau khi thực hiện lệnh "Xóa sử dụng không sử dụng"), đó là một dấu hiệu tốt cho thấy lớp bên trong tệp này đang hoạt động quá nhiều. Điều tương tự áp dụng cho kích thước của chính tập tin.

Trong khi xem xét mã, tôi đã tìm thấy một tệp 4.000 LỘC. Dường như tác giả của mã này chỉ đơn giản là sao chép cùng một phương thức 15 dòng hàng trăm lần, thay đổi một chút tên của các biến và phương thức được gọi. Một regex đơn giản được phép cắt tập tin từ 4.000 LỘC thành 500 LỘC, chỉ bằng cách thêm một vài khái quát; Tôi khá chắc chắn rằng với một phép tái cấu trúc thông minh hơn, lớp này có thể được giảm xuống còn vài chục dòng.

Bằng cách sử dụng các vùng, tác giả khuyến khích bản thân bỏ qua thực tế là mã không thể duy trì và được viết kém, và sao chép mã nhiều thay vì cấu trúc lại mã.

Khu vực làm một khu phố, khu vực làm khu vực này

Một ví dụ tuyệt vời khác là một phương thức khởi tạo quái vật chỉ đơn giản là thực hiện nhiệm vụ 1, sau đó là nhiệm vụ 2, sau đó là nhiệm vụ 3, v.v. Có năm hoặc sáu nhiệm vụ hoàn toàn độc lập, mỗi nhiệm vụ khởi tạo một thứ gì đó trong một lớp container. Tất cả các nhiệm vụ đó được nhóm thành một phương thức và được nhóm thành các khu vực.

Điều này có một lợi thế:

  • Phương pháp này khá rõ ràng để hiểu bằng cách nhìn vào tên khu vực. Điều này đang được nói, cùng một phương pháp một khi được tái cấu trúc sẽ rõ ràng như ban đầu.

Các vấn đề, mặt khác, là nhiều:

  • Không rõ ràng nếu có sự phụ thuộc giữa các khu vực. Hy vọng rằng, không có việc sử dụng lại các biến; nếu không, việc bảo trì có thể là một cơn ác mộng hơn nữa.

  • Phương pháp này gần như không thể kiểm tra. Làm thế nào bạn có thể dễ dàng biết nếu phương pháp thực hiện hai mươi điều một lần có đúng không?

Vùng trường, vùng thuộc tính, vùng xây dựng:

Mã được xem xét cũng chứa rất nhiều vùng nhóm tất cả các trường lại với nhau, tất cả các thuộc tính cùng nhau, v.v ... Điều này có một vấn đề rõ ràng: tăng trưởng mã nguồn.

Khi bạn mở một tệp và thấy một danh sách lớn các trường, bạn sẽ có xu hướng cấu trúc lại lớp trước, sau đó làm việc với mã. Với các vùng, bạn có thói quen thu gọn đồ đạc và quên nó đi.

Một vấn đề khác là nếu bạn làm điều đó ở mọi nơi, bạn sẽ thấy mình tạo ra các khu vực một khối, điều này không có ý nghĩa gì. Đây thực sự là trường hợp trong mã tôi đã xem xét, nơi có rất nhiều hàm #region Constructorchứa một hàm tạo.

Cuối cùng, các trường, thuộc tính, hàm tạo, v.v. đã có sẵn theo thứ tự . Nếu chúng là và chúng khớp với các quy ước (hằng số bắt đầu bằng chữ in hoa, v.v.), thì rõ ràng nơi loại phần tử dừng và bắt đầu khác, vì vậy bạn không cần phải tạo vùng rõ ràng cho điều đó.


13
Tôi nghĩ rằng có ít nhất một vài cách sử dụng có thể phòng thủ của #regions - ví dụ: thu gọn các mệnh đề bảo vệ (kiểm tra các tham số đầu vào), nếu không được giải mã, làm mất đi ý chính hoặc "thịt" của phương thức. Một ví dụ khác là xử lý ngoại lệ trên các ranh giới API; bạn thường không muốn tác động đến dấu vết ngăn xếp bằng cách gọi các phương thức khác để bọc ngoại lệ, vì vậy bạn có một vài dòng mã để bọc và suy nghĩ lại. Đây cũng thường là mã không liên quan và có thể được thu gọn một cách an toàn.
Daniel B

9
Kiểm tra thực tế. Tôi đã thấy rất nhiều #regions phương pháp hữu ích. Khi bạn đã có một phương thức hàng trăm dòng với logic điều khiển lồng nhau với hàng chục đến hàng trăm dòng với một số trong số đó - cảm ơn chúa, kẻ ngốc ít nhất đã đặt vào các khu vực.
radarbob 27/03/13

37
@radarbob: tóm lại, các khu vực rất hữu ích trong mã crappy không nên tồn tại ở nơi đầu tiên.
Arseni Mourzenko

41
-1 (nếu tôi có danh tiếng). Ngay cả khi các thành viên loại của bạn được tổ chức tốt và tách biệt, có thể có rất nhiều người trong số họ. Các khu vực giúp bạn tiết kiệm được việc phải cuộn qua 10 hoặc 12 thuộc tính và các getters và setters liên quan chỉ để đến một phương thức bạn muốn làm việc. Thay thế duy nhất là thu gọn tất cả các thuộc tính của bạn, đây không phải là thứ tôi hâm mộ. Các khu vực chức năng hiển thị / ẩn quy mô lớn cung cấp là cực kỳ hữu ích. Tôi đồng ý về các khu vực nội phương mặc dù.
Asad Saeeduddin

14
Tôi hoàn toàn không đồng ý với câu trả lời này: Mã hôi thối và khu vực không liên quan gì đến nhau. Nếu mã của bạn bốc mùi, nó sẽ bốc mùi có hoặc không có vùng. Cách tôi sử dụng các vùng là tách các lớp của tôi thành các vùng. Nói chung, tôi theo cùng một mẫu mặc dù: Thuộc tính công cộng, Phương thức công khai, Trường riêng, Phương thức riêng. Đó là sử dụng duy nhất tôi sẽ có khu vực cho. Bất cứ điều gì khác, có lẽ bạn đang phá vỡ SRP chính trong mã của bạn.
Alexus

113

Thật đáng kinh ngạc với tôi có bao nhiêu người ghét các khu vực rất say mê!

Tôi hoàn toàn đồng ý với rất nhiều ý kiến ​​phản đối của họ: Việc đẩy mã vào #regionđể che giấu nó khỏi tầm nhìn là một điều tồi tệ. Chia một lớp thành #regionskhi nó nên được tái cấu trúc thành các lớp riêng biệt rõ ràng là một sai lầm. Sử dụng một #regionđể nhúng thông tin ngữ nghĩa dư thừa là, tốt, dự phòng.

Nhưng không có điều gì trong số đó có nghĩa là có bất cứ điều gì vốn đã sai khi sử dụng các vùng trong mã của bạn! Tôi chỉ có thể giả định rằng hầu hết sự phản đối của mọi người đến từ việc làm việc trong các nhóm nơi những người khác có xu hướng sử dụng các tính năng IDE như thế này không chính xác. Tôi có sự thoải mái khi làm việc chính, và tôi đánh giá cao cách các khu vực đã giúp tổ chức quy trình làm việc của tôi. Có thể đó là chứng rối loạn ám ảnh cưỡng chế của tôi, nhưng tôi không muốn thấy một loạt mã trên màn hình của mình tại bất kỳ thời điểm nào, dù nó được viết gọn gàng và thanh lịch như thế nào. Việc tách các thứ ra thành các vùng logic cho phép tôi thu gọn mã mà tôi không quan tâm để làm việc với mã mà tôi làmquan tâm Tôi không bỏ qua mã được viết xấu, sẽ không có ý nghĩa để cấu trúc lại mã nhiều hơn nó và tổ chức "meta" bổ sung là mô tả, thay vì vô nghĩa.

Bây giờ tôi đã dành nhiều thời gian hơn để làm việc trong C ++, lập trình trực tiếp hơn cho API Windows, tôi thấy mình mong muốn rằng sự hỗ trợ cho các khu vực cũng tốt như đối với C #. Bạn có thể lập luận rằng việc sử dụng thư viện GUI thay thế sẽ giúp mã của tôi đơn giản hoặc rõ ràng hơn, do đó loại bỏ sự cần thiết phải loại bỏ tiếng ồn mã không liên quan ra khỏi màn hình, nhưng tôi có những lý do khác để không muốn làm điều đó. Tôi đủ thành thạo với bàn phím và IDE của mình rằng việc mở rộng / thu gọn mã được chia thành các vùng chỉ mất chưa đến một phần của giây. Thời gian tôi tiết kiệm trí lực, cố gắng giới hạn sự tập trung có ý thức của tôi vào chỉ mã mà tôi hiện đang làm việc, là đáng giá hơn thế. Tất cả đều thuộc về một lớp / tệp duy nhất, nhưng nó không thuộc về màn hình của tôi cùng một lúc.

Vấn đề là việc sử dụng #regionsđể phân tách và phân chia hợp lý mã của bạn không phải là điều xấu cần tránh bằng mọi giá. Như Ed chỉ ra, nó không phải là "mùi mã". Nếu mã của bạn có mùi, bạn có thể chắc chắn rằng nó không đến từ các khu vực, mà thay vào đó là từ bất kỳ mã nào bạn đã cố gắng chôn vùi trong các khu vực đó. Nếu một tính năng giúp bạn có tổ chức hơn, hoặc viết mã tốt hơn, thì tôi nói hãy sử dụng nó . Nếu nó trở thành một trở ngại, hoặc bạn thấy mình sử dụng nó không đúng cách, thì hãy ngừng sử dụng nó. Nếu điều tồi tệ nhất đến tồi tệ nhất và bạn buộc phải làm việc trong một nhóm với những người sử dụng nó, thì hãy ghi nhớ phím tắt để tắt mã phác thảo: Ctrl+ M, Ctrl+P. Và ngừng phàn nàn. Đôi khi tôi có cảm giác đây là một cách khác mà những người muốn được coi là lập trình viên "chân chính", "khó tính" thích thử và chứng tỏ bản thân. Bạn không nên tránh các vùng hơn là bạn đang tránh tô màu cú pháp. Nó không làm cho bạn trở thành một nhà phát triển máy móc hơn.

Tất cả điều đó đang được nói, các khu vực trong một phương pháp chỉ là vô nghĩa. Bất cứ khi nào bạn thấy mình muốn làm điều đó, bạn nên tái cấu trúc thành một phương pháp riêng biệt. Không có lời bào chữa.


9
Nói hay lắm. Việc sử dụng các vùng cho tổ chức không có hại hơn so với việc bật tùy chọn "xem khoảng trắng" của IDE. Đó là một sở thích cá nhân.
Josh

24
Làm việc trên WPF với ViewModels có 10 hoặc 20 thuộc tính chỉ đơn giản là bọc các thuộc tính trên mô hình của tôi, tôi yêu các vùng - Tôi chỉ có thể giấu các thuộc tính đó trong một khu vực (chúng không bao giờ cần phải chạm vào) và để mắt đếnliên quan .
Kirk Broadhurst

4
Hoàn toàn đồng ý. Trong .NET 2.0, các thuộc tính dài khoảng 8-10 dòng. Khi bạn có hơn 20 thuộc tính trong một lớp, chúng chiếm rất nhiều không gian. Các khu vực là hoàn hảo cho sụp đổ chúng.
Kristof Claes

6
@Kristof: Là các thuộc tính trong .NET 4.0 thực hiện xác nhận đầu vào đơn giản. Thuộc tính tự động không phải là tất cả những gì kỳ diệu cho mục đích của tôi.
Cody Grey

8
Tôi sẵn sàng đánh cược trái bóng của mình rằng những người ghét khu vực chưa bao giờ phát triển ứng dụng WPF hoặc chưa bao giờ thực sự sử dụng các chức năng xác định của WPF như ràng buộc dữ liệu và ràng buộc lệnh. Chỉ cần thiết lập mã của bạn để làm cho những công việc đó chiếm rất nhiều không gian và bạn thường không phải nhìn lại chúng.
l46kok

70

Trước hết, tôi không thể chịu được thuật ngữ "mùi mã" nữa. Nó được sử dụng quá thường xuyên và phần lớn thời gian của những người không thể nhận ra mã tốt nếu nó cắn chúng. Dù sao ...

Cá nhân tôi không thích sử dụng nhiều vùng. Điều này khiến việc lấy mã trở nên khó khăn hơn và mã là điều tôi quan tâm. Tôi thích các vùng khi tôi có một đoạn mã lớn mà không cần phải chạm thường xuyên. Bên cạnh đó, họ dường như cản trở tôi và các khu vực như "Phương pháp riêng tư", "Phương pháp công cộng", v.v ... chỉ khiến tôi phát điên. Chúng giống như ý kiến ​​của sự đa dạng i++ //increment i.

Tôi cũng sẽ nói thêm rằng việc sử dụng các vùng thực sự không thể là một "chống mẫu" vì thuật ngữ đó thường được sử dụng để mô tả các mẫu thiết kế / logic chương trình, không phải là bố cục của trình soạn thảo văn bản. Đây là chủ quan; Sử dụng những gì làm việc cho bạn. Bạn sẽ không bao giờ kết thúc với một chương trình không thể nhầm lẫn do bạn sử dụng quá mức các vùng, đó là những gì mà các mô hình chống lại là tất cả. :)


2
Thông thường tôi sẽ đánh giá thấp bạn về nhận xét mùi mã nhưng trong trường hợp này là chính xác. Không mã không thể là một mùi mã. +2!

7
Haha, tôi không có ý nói rằng thuật ngữ "mùi mã" không thể được sử dụng chính xác. Nó có thể, nhưng tôi thấy nó bị ném rất nhiều trong những ngày này đến nỗi phản ứng tức thời của tôi chỉ là sự khó chịu, đặc biệt là khi nó đến từ những người thực sự chỉ lặp lại những gì họ nghe mà không hiểu nó hoặc suy nghĩ nghiêm túc. Các câu như "hơn 5 biến cục bộ trong hàm là một mùi mã" chỉ cho thấy người đó thực sự có ít kinh nghiệm như thế nào.
Ed S.

13
Không chắc chắn tôi hiểu nhận xét của bạn về mùi mã. Mùi mã không cho thấy có vấn đề, chỉ có thể có vấn đề.
Craig

7
+1 để đứng lên với thuật ngữ mùi mã. Tôi đã phát ngán khi thấy một bài đăng tuyên bố các phương thức riêng tư là một mùi mã. Nhưng nói chung, tôi không đồng ý với sự chán ghét của bạn cho các khu vực. Tôi dễ bị phân tâm. Thực tế tôi rất thích nếu VS có chế độ VB4, tại đó bạn chỉ có thể hiển thị một phương thức duy nhất tại một thời điểm.
Josh

7
Chỉ muốn hô vang và nói rằng việc lạm dụng một phép ẩn dụ hoàn toàn tốt không nên làm giảm giá trị của phép ẩn dụ. "Mùi mã" là một phép ẩn dụ tuyệt vời, một từ được hiểu ngay lập tức, dễ nhớ và dễ sử dụng. Vẫn còn nhiều nơi áp dụng phép ẩn dụ "mùi mã" vẫn là cách tốt nhất để hiểu ý.
Eric King

23

Có vùng là một mùi mã!

Tôi rất vui khi thấy các khu vực bị xóa hoàn toàn khỏi trình biên dịch. Mỗi nhà phát triển đưa ra kế hoạch chải chuốt vô nghĩa của riêng mình sẽ không bao giờ có giá trị đối với một lập trình viên khác. Tôi có tất cả mọi thứ để làm với các lập trình viên muốn trang trí và làm đẹp cho em bé của họ, không có gì để làm với bất kỳ giá trị thực sự.

Bạn có thể nghĩ về một ví dụ mà bạn mặc dù "trời ạ, tôi ước đồng nghiệp của tôi đã sử dụng một số vùng ở đây!"?

Mặc dù tôi có thể định cấu hình IDE của mình để tự động mở rộng tất cả các vùng nhưng chúng vẫn gây nhức mắt và làm mất khả năng đọc mã thực.

Tôi thực sự quan tâm ít hơn nếu tất cả các phương thức công khai của tôi được kết hợp với nhau hay không. Xin chúc mừng bạn biết sự khác biệt giữa một khai báo biến và khởi tạo, không cần hiển thị nó trong mã!

Chải chuốt vô giá trị!

Ngoài ra, nếu tệp của bạn cần và 'kiến trúc thông tin' thông qua việc sử dụng các vùng bạn có thể muốn chống lại vấn đề cốt lõi: Lớp của bạn quá lớn! Chia nó thành các phần nhỏ có lợi hơn nhiều và khi được thực hiện đúng cách sẽ thêm ngữ nghĩa / khả năng đọc thực sự.


Là #regions một phần của trình biên dịch? Tôi nghĩ rằng họ chỉ là một chỉ thị cho IDE có thể bị bỏ qua.
Steve Rukuts

2
Trình biên dịch sẽ cần bỏ qua chúng khi phân tích mã C # của bạn. Nếu nó không bỏ qua chúng, nó sẽ ném lên chúng. Tôi có nghĩa là nó theo cách đó.
Joppe

1
"Bạn có thể nghĩ về một ví dụ mà bạn mặc dù" trời ạ, tôi ước đồng nghiệp của tôi đã sử dụng một số vùng ở đây! "?" Vâng, rất nhiều như vậy. Khi tôi có một lớp với các phương thức riêng và phương thức chung, tôi chia chúng thành các vùng vì khi tái cấu trúc các phương thức công khai, bạn không nhất thiết phải chạm vào mã riêng và ngược lại.
Anshul

Rõ ràng là bạn chưa bao giờ thấy mã thuê ngoài. Sooo nhiều lần các khu vực sẽ là tuyệt vời để xem trong mã thuê ngoài. Mặc dù mã này rất tệ, nhưng ít nhất nó sẽ dễ hiểu hơn rất nhiều nếu nó được nhóm lại với nhau theo một nghĩa hợp lý nào đó. Mặc dù, nếu mã của họ không có khả năng logic thì các vùng sẽ không có, vì vậy có lẽ sẽ làm cho nó tồi tệ hơn. Khu vực là tuyệt vời khi sử dụng đúng cách mặc dù.
Nickmccomb

15

Cá nhân tôi sử dụng các vùng như một cách để nhóm các loại phương thức hoặc các phần của mã với nhau.

Vì vậy, một tệp mã có thể trông như thế này khi mở nó:

  • Thuộc tính công cộng
  • Người xây dựng
  • Phương thức lưu
  • Chỉnh sửa phương pháp
  • Phương pháp trợ giúp riêng

Tôi không đặt các vùng bên trong các phương thức. IMHO đó là một dấu hiệu của mùi mã. Tôi đã từng bắt gặp một phương pháp dài hơn 1200 dòng và có 5 vùng khác nhau trong đó. Đó là một cảnh tượng đáng sợ!

Nếu bạn đang sử dụng nó như một cách để tổ chức mã của mình theo cách sẽ giúp việc tìm kiếm mọi thứ nhanh hơn cho các nhà phát triển khác, tôi không nghĩ đó là một dấu hiệu rắc rối. Nếu bạn đang sử dụng nó để ẩn các dòng mã bên trong một phương thức, tôi sẽ nói rằng đã đến lúc phải suy nghĩ lại về phương thức đó.


14
Ừ Tôi biết đây là một chủ đề chủ quan, nhưng anh bạn, tôi thực sự không thể chịu được kế hoạch này. Theo kinh nghiệm của tôi, 'tổ chức' được thêm vào hoàn toàn không giúp ích gì và nó chỉ khiến việc duyệt mã trở nên khó khăn. Tôi cũng thích các phương pháp nhóm không chỉ bằng cách sửa đổi truy cập mà bởi trách nhiệm logic. Đối với giao diện công cộng, tôi thường nhóm từng phương thức / thuộc tính lại với nhau, nhưng thường thì phương thức được bảo vệ có thể gọi hàm trợ giúp riêng và trong trường hợp đó tôi rất thích hàm trợ giúp (chỉ có thể được sử dụng ở đó) ở trên hoặc dưới phương pháp gọi nó.
Ed S.

3
@Ed S. - đó là lý do tại sao tôi nói "có thể trông như thế". Nó rất chủ quan. Tôi không nói rằng mọi tập tin sẽ trông như thế. Tôi sẽ ngạc nhiên nếu họ đã làm. Chỉ là một ví dụ về một chủ đề phức tạp. :)
Tyanna

Ồ tôi biết, như tôi đã nói; đó là chủ quan. Bất cứ điều gì làm việc cho bạn / nhóm của bạn. Tôi chỉ đưa ra kế hoạch này vì nó không hoạt động (đối với tôi), nhưng tôi phải duy trì một dự án đã làm điều này. Nó làm tôi phát điên.
Ed S.

3
@ Chỉnh sửa. Vì vậy, đi vào tùy chọn của bạn trong vs và tắt các khu vực. Vấn đề được giải quyết.
Andy

Tại sao các đối tượng của bạn có phương thức lưu? :(
TheCatWhisperer

10

Sử dụng #regioncác khối để làm cho một lớp rất lớn có thể đọc được thường là dấu hiệu vi phạm Nguyên tắc Trách nhiệm duy nhất. Nếu chúng được sử dụng để hành vi nhóm, thì cũng có khả năng lớp đó đang làm quá nhiều (một lần nữa vi phạm SRP).

Bám sát dòng suy nghĩ "mùi mã", #regioncác khối không phải là mã tự ngửi mà thay vào đó chúng là "Febreze cho mã" hơn ở chỗ chúng cố gắng che giấu mùi. Trong khi trước đây tôi đã sử dụng chúng một tấn, khi bạn bắt đầu tái cấu trúc, bạn bắt đầu thấy ít hơn vì cuối cùng chúng không che giấu nhiều.


5

Từ khóa ở đây là "đúng đắn". Thật khó để tưởng tượng một trường hợp đặt một khu vực trong một phương thức là hợp lý; đó là tất cả quá có khả năng là ẩn mã và lười biếng. Tuy nhiên, có thể có những lý do chính đáng để có một vài vùng ở đây và ở đó trong mã của một người.

Nếu có rất nhiều khu vực, tôi nghĩ đó là mùi mã. Các khu vực thường là một gợi ý tại một nơi có thể để tái cấu trúc trong tương lai. Rất nhiều khu vực có nghĩa là ai đó thực sự không bao giờ thực hiện gợi ý.

Được sử dụng một cách thận trọng, chúng đưa ra một nền tảng tốt giữa cấu trúc của một lớp duy nhất với nhiều phương thức và cấu trúc của nhiều lớp chỉ với một vài phương thức trong mỗi lớp. Chúng rất hữu ích khi một lớp bắt đầu tiến gần đến điểm mà nó sẽ được tái cấu trúc thành nhiều lớp, nhưng vẫn chưa hoàn thành. Bằng cách nhóm các phương thức liên quan lại với nhau, sau này tôi dễ dàng trích xuất một tập hợp các phương thức liên quan vào lớp riêng của chúng nếu chúng tiếp tục tăng số lượng. Ví dụ: nếu tôi có một lớp đang tiếp cận 500 dòng mã, thì tập hợp các phương thức sử dụng tổng cộng 200 dòng mã được thu thập trong một vùng có lẽ là một phần tốt để tái cấu trúc bằng cách nào đó - và vùng khác có 100 dòng mã phương pháp cũng có thể là một mục tiêu tốt.

Một cách khác mà tôi muốn sử dụng các vùng là giảm một trong những tác động tiêu cực của việc tái cấu trúc một phương thức lớn: Rất nhiều phương thức nhỏ, ngắn gọn, dễ sử dụng mà người đọc phải cuộn qua để đến một phương pháp khác không liên quan. Một vùng có thể là một cách hay để đóng gói meta một phương thức và các trợ giúp của nó cho các độc giả, vì vậy ai đó đang làm việc với một khía cạnh khác của lớp có thể thu gọn chúng và nhanh chóng loại bỏ phần mã đó. Tất nhiên, điều này chỉ hoạt động nếu các khu vực của bạn thực sự được tổ chức tốt và về cơ bản được sử dụng như một cách khác để ghi lại mã của bạn.

Nói chung, tôi thấy các vùng giúp tôi giữ bản thân ngăn nắp, giúp "ghi lại" mã của mình và giúp tôi bắt các địa điểm để tái cấu trúc sớm hơn nhiều so với việc tôi không sử dụng các vùng.


4

Tôi chủ yếu sử dụng các vùng cho các lớp máy chủ CRUD để tổ chức các loại hoạt động khác nhau. Thậm chí sau đó, tôi có thể vui vẻ đi mà không có họ.

Nếu được sử dụng rộng rãi, nó sẽ giương cờ đỏ. Tôi sẽ đề phòng các lớp học có quá nhiều trách nhiệm.

Theo kinh nghiệm của tôi, một phương thức với hàng trăm dòng mã chắc chắn là một mùi.


4

Nguyên tắc nhỏ của tôi là: Nếu bạn có nhiều hơn 5 vùng trong một tệp thì đó là mùi mã

Tức là, có thể tốt khi phân định trường, phương thức, thuộc tính và hàm tạo, nhưng nếu bạn bắt đầu bao bọc mọi phương thức khác trong một khu vực thì điều đó là sai.

.. và vâng, tôi đã tham gia rất nhiều dự án trong trường hợp đó, thường là do các tiêu chuẩn mã hóa kém, tạo mã hoặc cả hai. Nó trở nên cũ kỹ nhanh chóng khi phải chuyển đổi tất cả các phác thảo trong phòng thu trực quan để có được một cái nhìn tổng quan về mã.


4

KHU VỰC CÓ SỬ DỤNG

Tôi đã từng sử dụng chúng cho các sự kiện giao diện "mã hóa tay" trước đây cho các ứng dụng Windows dạng.

Tuy nhiên, trong công việc của tôi, chúng tôi sử dụng một trình tạo mã để xử lý SQL và nó tự động sử dụng các vùng để sắp xếp các loại phương thức chọn, cập nhật, xóa, v.v.

Vì vậy, trong khi tôi không sử dụng chúng thường xuyên, chúng hoàn toàn ổn để loại bỏ các đoạn mã lớn.


1
Tôi đã sử dụng các trình tạo mã tương tự và thích sử dụng các lớp một phần để loại bỏ mã được tạo.
Craig

Chúng tôi làm, các vùng nằm trong mã được tạo để giúp đọc hoặc gỡ lỗi dễ dàng hơn (nếu cần).
Ken

4

Nếu bạn có mã vùng IN, chắc chắn bạn có vấn đề (chặn trường hợp mã được tạo.) Đặt vùng vào mã về cơ bản là nói "tái cấu trúc mã này".

Tuy nhiên, có những trường hợp khác. Một điều mà tôi nghĩ rằng tôi đã làm một lúc trước: Một cái bàn có vài ngàn vật phẩm được tính toán trước trong đó. Đó là một mô tả về hình học, thiếu một lỗi trong bảng sẽ không bao giờ có dịp để xem xét nó. Chắc chắn, tôi có thể đã thu được dữ liệu từ một tài nguyên hoặc tương tự nhưng điều đó sẽ ngăn cản việc sử dụng trình biên dịch để giúp dễ đọc.


1
Đó là trường hợp sử dụng tốt hơn cho một lớp một phần với tệp được lưu trữ trong một tệp riêng biệt hoặc có thể là IMyDataSource được tiêm với triển khai HardcodingDataSource.
Bryan Boettcher

3

Trong một dự án gần đây, có một phương thức 1700 dòng với một số vùng được nhúng trong đó. Điều thú vị là các khu vực đã giải phóng các hành động khác biệt đang được thực hiện trong phương thức. Tôi đã có thể thực hiện một phương thức tái cấu trúc -> trích xuất trên từng vùng mà không ảnh hưởng đến chức năng của mã.

Nói chung, các khu vực được sử dụng để ẩn mã tấm nồi hơi là hữu ích. Tôi sẽ khuyên bạn không nên sử dụng các vùng để ẩn các thuộc tính, các trường và những thứ tương tự bởi vì nếu chúng quá khó sử dụng khi làm việc trong lớp, có lẽ đó là dấu hiệu cho thấy lớp học sẽ bị phá vỡ thêm. Nhưng như một quy tắc cứng, nếu bạn đặt một vùng trong một phương thức, có lẽ bạn nên trích xuất một phương thức khác giải thích những gì đang xảy ra hơn là bọc khối đó trong một vùng.


3

Các khu vực có thể được sử dụng trong mã có chất lượng tốt? Có lẽ. Tôi cá là họ, trong nhiều trường hợp. Tuy nhiên, trải nghiệm cá nhân của tôi khiến tôi rất nghi ngờ - tôi đã thấy các khu vực hầu như chỉ bị lạm dụng. Tôi nói rằng tôi đã chán nản, nhưng vẫn lạc quan.

Tôi gần như có thể chia mã sử dụng vùng mà tôi đã thấy cho đến nay thành ba loại:

  • Mã được bao thanh toán kém: Hầu hết các mã mà tôi thấy sử dụng các vùng làm công cụ bao thanh toán của người nghèo. Ví dụ, một lớp đã phát triển đến mức có ý nghĩa để chuyên môn hóa nó cho các mục đích khác nhau có thể được chia thành các khu vực riêng biệt, mỗi khu vực cho mỗi mục đích.

  • Mã được viết bằng cách sử dụng các thư viện sai và đôi khi là ngôn ngữ sai cho miền vấn đề Thông thường, khi lập trình viên không sử dụng đúng bộ thư viện cho miền có vấn đề, bạn sẽ thấy mã trở nên dài dòng vô cùng - với rất nhiều chức năng trợ giúp nhỏ cái mà thực sự không thuộc về (có lẽ chúng thuộc về thư viện của riêng họ).

  • Mã được viết bởi sinh viên hoặc sinh viên tốt nghiệp gần đây. Một số chương trình và khóa học dường như cố gắng và khắc sâu sinh viên với việc sử dụng các khu vực cho tất cả các mục đích lạ. Bạn sẽ thấy các khu vực xả rác mã nguồn đến điểm mà tỷ lệ thẻ khu vực so với các dòng mã nằm trong phạm vi 1: 5 hoặc tệ hơn.


3

Tôi sẽ nói đó là một "mùi mã."

Chống mẫu nói chung là các vấn đề cấu trúc cơ bản trong một phần mềm, trong khi các vùng, tự chúng chỉ gây ra một hành vi đáng ghét trong một trình soạn thảo. Sử dụng các vùng không thực sự xấu, nhưng sử dụng chúng rất nhiều, đặc biệt là để ẩn các đoạn mã có thể cho thấy có những vấn đề khác, độc lập và lớn hơn đang diễn ra ở nơi khác.


@Andrew Grimm: yeah
whatsisname

3

Tôi chỉ sử dụng các vùng cho một thứ (ít nhất là tôi không thể nghĩ đến những nơi khác tôi sử dụng chúng): để nhóm các bài kiểm tra đơn vị cho một phương pháp.

Tôi thường có một lớp kiểm tra cho mỗi lớp và sau đó nhóm các bài kiểm tra đơn vị cho mỗi phương thức bằng cách sử dụng các vùng có tên của phương thức. Không chắc đó có phải là mùi mã hay gì không, nhưng vì ý tưởng cơ bản là các thử nghiệm đơn vị không cần thay đổi trừ khi chúng bị hỏng vì có gì đó trong mã thay đổi, giúp tôi dễ dàng tìm thấy tất cả các thử nghiệm cho một phương pháp cụ thể khá nhanh chóng.

Tôi có thể đã sử dụng các vùng để tổ chức mã trong quá khứ, nhưng tôi không thể nhớ lần cuối cùng tôi đã làm điều đó. Tôi dính vào các khu vực của tôi trong các lớp kiểm tra đơn vị mặc dù.


1
Bạn có bao giờ có các bài kiểm tra kiểm tra nhiều hơn một phương pháp?
Marcie

Tôi không thực sự hiểu câu hỏi hoặc những gì bạn đang nhắm đến nó. Câu trả lời là: Không, một bài kiểm tra đơn vị luôn được nhắm mục tiêu chỉ theo một phương thức hoặc đúng hơn là một khía cạnh nhất định của một phương thức.
Anne Schuessler

2

Tôi tin rằng đó là một mô hình chống và thẳng thắn nghĩ rằng chúng nên được loại bỏ. Nhưng nếu bạn không may làm việc ở một nơi mà họ là một Visual Studio tiêu chuẩn cung cấp một công cụ tuyệt vời để giảm thiểu số lượng bạn muốn nôn mửa mỗi khi bạn thấy một khu vực tôi ghét #Regions

Plugin này sẽ tối đa kích thước phông chữ của các vùng thực sự nhỏ. Chúng cũng sẽ được mở rộng để bạn không phải nhấn ctr + m + l để mở tất cả các vùng. Nó không khắc phục được dạng ung thư mã này nhưng nó có thể chịu được.


0

Tôi sử dụng các vùng để chứa từng kết hợp tầm nhìn và loại thành viên. Vì vậy, tất cả các chức năng riêng tư đi vào một khu vực, vv

Lý do tôi làm điều này không phải vì vậy tôi có thể gấp mã. Đó là bởi vì tôi đã soạn thảo kịch bản của mình để tôi có thể chèn, giả sử, một tham chiếu đến proxy:

#region "private_static_members"
 /// <summary>
 /// cache for LauncherProxy
 /// </summary>
private static LauncherProxy _launcherProxy;
#endregion

#region "protected_const_properties"
protected LauncherProxy LauncherProxy{
  get{
    if(_launcherProxy==null) {
      if (!God.Iam.HasProxy(LauncherProxy.NAME)) {
        God.Iam.RegisterProxy(new LauncherProxy());
      }
      _launcherProxy=God.Iam.Proxy(LauncherProxy.NAME) as LauncherProxy;
    }
    return _launcherProxy;
  }
}
#endregion

vào mã và có từng phần gọn gàng vào khu vực thích hợp.

Trong trường hợp này, macro sẽ phân tích dự án của tôi, đưa cho tôi một danh sách các proxy và tiêm mã cho cái tôi muốn. Con trỏ của tôi thậm chí không di chuyển.

Khi bắt đầu học C #, tôi đã cân nhắc việc sử dụng các khu vực để giữ sự phổ biến cùng nhau, nhưng đó là một đề xuất không thành công bởi vì nó không phải là mối quan hệ một-một lúc nào. Ai muốn băn khoăn về một thành viên được sử dụng bởi hai khu vực, hoặc thậm chí bắt đầu phá vỡ mọi thứ theo các điều khoản đó.

Loại phân tách duy nhất khác là các phương thức - Tôi sẽ chia các phương thức thành các Lệnh, Hàm và Trình xử lý, vì vậy tôi sẽ có một vùng dành cho các lệnh công khai, riêng tư, v.v.

Điều này mang lại cho tôi độ chi tiết, nhưng nó là nhất quán, độ chi tiết không rõ ràng mà tôi có thể dựa vào.


-1 ngay khi tôi nhận được 125 điểm để downvote. Bạn đang thêm các dòng mã không cần thiết. TẠI SAO TẠI SAO TẠI SAO bạn sẽ đặt một khu vực xung quanh một tài sản ... nếu (God.Iam.AbusingRegions () == true) myName = "Mark"
DeadlyChambers

1
@DeadlyChambers Lý do được nêu trong đoạn thứ hai - Tôi đang sử dụng macro trình soạn thảo để chèn các mẫu mã phổ biến vào tệp, các vùng giúp giữ tệp có cấu trúc để các mục tương tự được nhóm lại. Tôi không đặt một khu vực xung quanh một thuộc tính riêng lẻ, nhưng tất cả các thuộc tính rơi vào một khu vực được chỉ định tùy thuộc vào thuộc tính của chúng "bảo vệ_const_properies". Bạn đã đọc bài viết??
Đánh dấu

1
Bạn có thể có thể cấu trúc lại thành: LauncherProxy LauncherProxy được bảo vệ => God.Iam.GetOrAddProxy <LauncherProxy> (ref _launcherProxy); và do đó bạn không cần khu vực. Ngoài ra, _launcherProxy có thể được đổi tên thành _launcherProxyCache để bạn không cần khu vực cũng như bình luận ở đó.
aeroson

0

Các vùng là các biểu thức tiền xử lý - nói cách khác, chúng được xử lý như các bình luận và về cơ bản bị bỏ qua bởi trình biên dịch. Chúng hoàn toàn là một công cụ trực quan được sử dụng trong Visual Studio. Do đó, #region không thực sự là mùi mã, vì nó không phải là mã. Mùi mã thay vì phương thức 800 dòng có nhiều trách nhiệm khác nhau được nhúng trong v.v. Vì vậy, nếu bạn thấy 10 vùng trong một phương thức - có thể nó được sử dụng để ẩn mùi mã. Phải nói rằng tôi đã thấy chúng được sử dụng cực kỳ hiệu quả để làm cho một lớp trở nên dễ chịu hơn và dễ điều hướng hơn - trong một lớp được viết và cấu trúc rất tốt!


0

Các khu vực là một ý tưởng tổ chức tiện lợi, nhưng không tính đến một số xu hướng của nhà phát triển muốn phân loại mọi thứ và nói chung là không cần thiết theo hầu hết các thực tiễn OOP hiện đại ... chúng là một "mùi", theo nghĩa là sử dụng chúng thường chỉ ra rằng lớp / phương thức của bạn quá lớn và cần được cấu trúc lại, vì bạn có khả năng vi phạm "S" của các nguyên tắc RẮN ... nhưng giống như bất kỳ mùi nào, nó không nhất thiết phải có nghĩa là có gì đó xấu đi.

Các khu vực phục vụ nhiều mục đích hơn trong mã chức năng thay vì mã hướng đối tượng, IMO, nơi bạn có các chức năng dài của dữ liệu tuần tự có ý nghĩa để chia tay, nhưng đã có lần tôi đã sử dụng chúng trong c # và hầu như chúng luôn luôn tập trung vào mã mà bạn không cần / muốn xem. Đối với tôi, đây thường là các hằng chuỗi SQL thô trong cơ sở mã được sử dụng cho NPoco hoặc các biến thể của nó. Trừ khi bạn thực sự quan tâm làm thế nào dữ liệu điền vào đối tượng POCO thông qua ORM của bạn, những thứ này hoàn toàn vô nghĩa khi nhìn vào ... và nếu bạn quan tâm, thì, hãy mở rộng vùng và BAM! Hơn 150 dòng của một số truy vấn SQL phức tạp cho niềm vui xem của bạn.

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.