Tại sao sử dụng các lớp một phần?


72

Theo hiểu biết của tôi, partialtừ khóa không làm gì ngoài việc cho phép một lớp được phân chia giữa một số tệp nguồn. Có bất kỳ lý do để làm điều này ngoài việc tổ chức mã? Tôi đã thấy nó được sử dụng cho điều đó trong các lớp UI được tạo.

Có vẻ như một lý do kém để tạo ra một từ khóa toàn bộ. Nếu một lớp đủ lớn để yêu cầu nhiều tệp, có lẽ nó đang làm quá nhiều. Tôi nghĩ rằng có lẽ bạn có thể sử dụng nó để xác định một phần một lớp cho một lập trình viên khác ở đâu đó để hoàn thành, nhưng sẽ tốt hơn nếu tạo một lớp trừu tượng.


10
Nó cũng không thực sự là một "toàn bộ từ khóa". Đó là một từ khóa theo ngữ cảnh . partialchỉ có nghĩa là một cái gì đó khi nó đến trước class. Bạn có thể sử dụng nó làm tên định danh trong các phần khác của mã, v.v.
Dean Harding

4
Nếu bạn sử dụng chúng và nó không dành cho mã được tạo, tôi ghét bạn. Không phải cá nhân bạn, nhưng bạn nói chung. Tôi ghét săn lùng mã thông qua các lớp một phần.
Steven Evers

3
Không khó để "săn mã", tất cả các phương thức lớp vẫn hiển thị trong phần thả xuống trong VS, bất kể phần nào của phần bạn đang xem. Các điều hướng mã khác cũng hoạt động tốt (cả điều hướng kiểu R # "thông minh" hoặc shift-ctrl-f cũ tốt
Steve

2
Đó là một sự hiểu lầm rằng các lớp một phần phải nằm trong các tệp riêng biệt.
Bart

Câu trả lời:


110

Nó rất hữu ích trong mọi kịch bản trong đó một phần của lớp được tạo bởi một công cụ tùy chỉnh vì nó cho phép bạn thêm logic tùy chỉnh vào mã được tạo mà không cần kế thừa lớp được tạo. Btw. cũng có một số phương pháp cho cùng một lý do.

Không chỉ về UI mà cả các công nghệ khác như Linq-To-Sql hay Entity Framework cũng sử dụng điều này khá nhiều.


44
Ngoài ra, nó cho phép bạn giữ mã của mình dưới sự kiểm soát phiên bản trong khi để mã được tạo ra khỏi kiểm soát phiên bản.
Frank Shearar

3
Điểm tốt, tôi chưa bao giờ nghĩ về điều đó. Tôi chỉ thấy nó bị lạm dụng trong thực tế. Một cách để các lập trình viên (tệ hại) giữ kích thước tệp có thể quản lý được.
Martin Wickman

1
Các ví dụ tốt nhất tôi đã sử dụng là: a) cho bối cảnh dữ liệu Linq to SQL nơi bạn muốn mở rộng các lớp; b) để mở rộng các lớp được truyền từ các dịch vụ web. Trong cả hai trường hợp, đây không phải là lạm dụng cũng không phải là phương tiện để giữ cho kích thước tệp có thể quản lý được ... Tôi hoàn toàn không vui khi thấy nó được sử dụng theo cách đó (và sẽ thực hiện các bước ...)
Murph

3
Các lớp WinForm sử dụng nó để ẩn tất cả các điều khiển tạo mã của nhà thiết kế (đặc biệt quan trọng vì nhà thiết kế thích sắp xếp lại ngẫu nhiên tất cả các mã mà nó tạo ra dẫn đến sự lộn xộn lớn khi diff / blaming) và nếu bạn đang làm việc với XML, công cụ XSD có thể tạo một phần các lớp khỏi tệp lược đồ một lần nữa cho phép bạn tách mã của mình khỏi sắp xếp được tạo tự động.
Dan Neely

2
@MartinWickman không nhất thiết là tệ hại. Đó là một điểm khởi đầu tốt để tái cấu trúc các đối tượng của Chúa trong mã kế thừa. Trước tiên, hãy cố gắng xóa cảnh quan bằng cách tách các lớp lớn thành các tệp riêng biệt. (Tôi biết nhận xét của bạn rất cũ)
Konrad Morawski

26

Như bạn nói, nó thường được sử dụng để tách mã được tạo. Nó thường không có gì để làm với kích thước của các lớp / tệp.

Lợi ích của việc tách mã được tạo là một trong những kiểu. Mã được tạo có thể khá xấu và không thể đọc được và sẽ thất bại nhiều tiêu chuẩn mã hóa (và kiểm tra StyleCop), nhưng không sao, không ai phải đọc hoặc duy trì trực tiếp. Vì vậy, nếu bạn "ẩn" nó trong một tệp khác, bạn có thể tập trung vào việc đảm bảo phần còn lại của lớp đạt tiêu chuẩn, vượt qua kiểm tra StyleCop, v.v.

Một lĩnh vực khác mà tôi đã sử dụng đó là nơi một lớp thực hiện nhiều giao diện, có thể khá hay để tách việc thực hiện thành các tệp riêng biệt, mặc dù đây là vấn đề sở thích cá nhân, tôi chưa bao giờ thấy bất kỳ tiêu chuẩn mã hóa nào yêu cầu ( hoặc ngăn chặn) điều này.


9
Tôi chưa bao giờ nghĩ đến việc sử dụng các phần của lớp để phân tách việc triển khai giao diện, đó là một ý tưởng tuyệt vời.
Đánh dấu gian hàng

Đó là về nhiều hơn phong cách. Các nhà phát triển của trình tạo mã sẽ phải nhảy qua các vòng để cho phép bạn chỉnh sửa mã trong tệp do trình tạo quản lý và thậm chí sau đó sẽ có vấn đề. Lợi ích số 1, với tôi, là cho bạn một nơi để viết mã mà trình tạo sẽ / không thể chạm vào. Đây là một lợi ích khá hữu hình.
Daniel

19

Một trong những nhà phát triển nơi tôi làm việc đã sử dụng một cách khá tốt cho họ vài tuần trước trong việc tái cấu trúc các lớp Thần khổng lồ đã vượt khỏi tầm kiểm soát và có rất nhiều phương pháp công khai: bằng cách tách rời các chức năng logic của từng bit lớp thành một lớp riêng biệt, bạn có thể tách lớp thành các đơn vị nguyên tử hơn nên là lớp mà không phá vỡ bất kỳ chức năng hiện có nào, cho phép bạn xem cái gì là phổ biến và cái gì không. Với điều này là giai đoạn đầu tiên, sau đó bạn có thể dễ dàng chia các phần ra thành các lớp độc lập của riêng mình và triển khai chúng trong toàn bộ cơ sở mã. Tôi nghĩ rằng đây là một ý tưởng tốt.

Tuy nhiên, nói chung tôi nghĩ rằng chúng chỉ nên được sử dụng để tăng các lớp được tạo bằng máy khi viết mã mới.


1
Tôi có thể thấy làm thế nào có thể có ích. Cho dù đó là lý do để nó có trong ngôn ngữ hay không ... tôi không biết. Máy tạo mã là một câu chuyện khác, mặc dù.
Michael K

2
Vâng, đó không phải là một lời biện minh cho ngôn ngữ này, nhưng đó là một cách thú vị để sử dụng chúng.

18

Tôi có thể nghĩ ra một vài tình huống hữu ích trong đó các phần có ý nghĩa, hầu hết trong số chúng tôi đang sử dụng bản thân mình trong các dự án của mình:

  • Để tách mã được tạo bởi Tool / IDE / Designer từ mã bạn đang duy trì. Một ví dụ điển hình là Form.Designer.cstệp chứa mã được tạo bởi nhà thiết kế cho các ứng dụng của Windows. Nhiều định dạng .NET khác cũng có một số mã được tạo bởi công cụ, có thể được tạo lại khi bạn xây dựng dự án của mình và do đó, tất cả các thay đổi tùy chỉnh của bạn sẽ bị xóa. Việc tách sẽ giúp bạn giữ mã của bạn và thay đổi an toàn khỏi các sửa đổi tự động như vậy.

  • Khi bạn đang thực hiện nhiều giao diện với rất nhiều mã trong quá trình thực hiện. Tôi có xu hướng sử dụng một phần riêng biệt cho mỗi giao diện như vậy, đặt tên như thế này : {Class}.{Interface}.cs. Nó rất dễ dàng cho tôi để xem trong IDE mà giao diện người {Class}đang thực hiện và làm thế nào.

  • Khi lớp phải chứa một hoặc nhiều lớp lồng nhau , đặc biệt là có đủ mã trong đó để được đưa vào một tệp riêng. Tôi sẽ bám vào mẫu trên và sử dụng {Class}.{NestedClass}.csquy ước đặt tên cho mỗi lớp lồng nhau. Thực tế tương tự đã được đề cập bởi câu trả lời của Virtlink .

  • Khi tôi viết staticcác lớp sẽ giữ các phương thức mở rộng . Nó thường sẽ là trường hợp để cung cấp logic phương thức mở rộng tương tự cho các lớp hoặc giao diện tương tự - ví dụ như Reversetrên các bộ sưu tập chung và không chung. Tôi sẽ đặt tất cả các phương thức mở rộng cho một lớp hoặc giao diện trong một phần riêng biệt của lớp tĩnh. Chẳng hạn, tôi có tất cả các phương thức mở rộng cho IListgiao diện ở một nơi và các phương thức tương tự dành cho IList<T>một tệp khác. Một cách tiếp cận khác là đặt cùng một phương thức (tất cả các quá tải của nó) trong cùng một phần, với tất cả các lớp có thể cho thistham số - giống như có tất cảReversethực hiện trong một tập tin. Nó phụ thuộc vào cái nào sẽ chứng minh tốt hơn sự phân tách về mặt khối lượng mã, hoặc một số quy ước nội bộ mà bạn hoặc tổ chức của bạn có thể tuân thủ.

  • Tôi không sử dụng điều này, nhưng tôi đã thấy một số người C / C ++ thích cách tiếp cận mà tôi sẽ mô tả ở đây: tạo một phần cho lớp chỉ bằng các phương thức một phần . Điều này giống với cách C / C ++ để xác định giao diện và tách biệt khai báo phương thức khỏi việc thực hiện.

  • Tách biệt bởi mối quan tâm hoàn toàn hợp lý . Nếu bạn tình cờ làm việc với một lớp lớn kết hợp nhiều bộ hoạt động logic, thì bạn có thể tách từng mã liên quan đến logic thành một phần riêng biệt. Thông thường sự tồn tại của các lớp như vậy là trái với nguyên tắc phân tách mối quan tâm , nhưng nó thường được quan sát trong trường hợp thực tế, đặc biệt là đối với các cơ sở mã cũ. Người dùng đồng nghiệp Steve Evers đã đề cập đến chúng trong câu trả lời của mình cho câu hỏi này , đề cập đến chúng bằng tên các đối tượng thần. Cá nhân tôi sử dụng cách tiếp cận của các lớp một phần để phân tách mã trước khi bất kỳ việc tái cấu trúc các tệp thực sự lớn như vậy diễn ra, để giảm bớt công việc của tôi và làm cho việc tái cấu trúc trở nên minh bạch hơn. Điều này cũng sẽ làm giảm các xung đột mà tôi có khả năng gây ra khi tham gia các hệ thống phiên bản như SVN.


14

Tôi chưa từng thấy nó được đề cập bởi bất kỳ ai: Tôi sử dụng partialđể đặt các lớp lồng nhau trong các tệp của riêng họ.

Tất cả các tệp mã của tôi chỉ chứa một lớp, struct, giao diện hoặc enum. Nó giúp việc tìm định nghĩa cho một đối tượng dễ dàng hơn rất nhiều khi tên tệp hiển thị tên của thứ bạn đang tìm kiếm. Và vì Visual Studio cố gắng khớp các thư mục dự án với các không gian tên, tên tệp phải khớp với các lớp.

Điều này cũng có nghĩa là một lớp được NestedClasslồng bên trong MyClasssẽ có tệp riêng trong các dự án của tôi : MyClass.NestedClass.cs.

partial class MyClass
{
    private class NestedClass
    {
        // ...
    }
}

1
Tôi tự hỏi tại sao một người sẽ bỏ phiếu trả lời này. Thực tiễn được đề cập không phải là một mô hình chống, cũng không gây ra bất kỳ vấn đề nào tôi biết.
Ivaylo Slavov

1
Điều này cũng giải quyết vấn đề giữ các tệp lớp nhỏ (về các dòng mã) trong khi vẫn cho phép đóng gói mã đúng trong một lớp bên trong.
redcalx

10

Ngoại trừ việc sử dụng mã được tạo, tôi chỉ thấy chúng được sử dụng trong nỗ lực che đậy cho các đối tượng thần . Cố gắng hiểu một cơ sở mã mới hoặc điều hướng qua nhiều tệp nguồn, cùng một đối tượng, thật khó chịu.

Vì vậy, khi bạn hỏi Why use partial classes?tôi trả lời: trừ khi bạn đang sử dụng mã được tạo, đừng.


+1. Đây là lần đầu tiên tôi thấy những loại đối tượng này được gọi là một tên (đối tượng thần) và nó thậm chí còn chính thức. Không bao giờ là quá muộn để học một cái gì đó mới.
Ivaylo Slavov

6

Mã tổ chức là lý do duy nhất, nhưng nó đi sâu hơn lúc đầu dường như. Nếu bạn có các lớp một phần nơi các phần được tạo, bạn có thể dễ dàng:

  • Tạo lại mã mà không phải phát hiện các thay đổi thủ công trong các lớp bạn viết (để bạn không ghi đè lên các phần đó).
  • Loại trừ các lớp một phần được tạo ra khỏi phạm vi kiểm tra, kiểm soát nguồn, số liệu, v.v.
  • Sử dụng mã được tạo mà không buộc bạn phải dựa trên chiến lược kế thừa của mình (bạn vẫn có thể kế thừa từ các lớp khác).

1

Cũng có một vài nơi mà các lớp được tạo / ngụ ý được khai báo một phần vì vậy nếu Dev cần mở rộng chúng, họ có quyền truy cập đầy đủ mà không phải lo lắng về việc kế thừa và ghi đè khắp nơi. Nhìn vào các lớp được tạo trong khu vực temp asp.net sau khi bạn chạy một trang web biểu mẫu web lần đầu tiên trong IIS nếu bạn muốn thử bắt một số ví dụ.


1

Tôi có thể nghĩ về việc sử dụng bẩn cho họ.

Giả sử bạn có một số lớp cần chức năng chung, nhưng bạn không muốn đưa chức năng đó vào chuỗi thừa kế phía trên chúng. Hoặc, bạn có một tập hợp các lớp sử dụng một lớp trợ giúp chung.

Về cơ bản bạn muốn làm nhiều kế thừa nhưng C # không thích. Vì vậy, những gì bạn làm là sử dụng một phần để tạo ra những gì thực chất là một #include trong C / C ++;

Đặt tất cả các chức năng vào một lớp hoặc sử dụng lớp trợ giúp. Sau đó sao chép trình trợ giúp X lần và đổi tên thành một phần lớp A, B, C. và đặt một phần vào các lớp A, B, C của bạn.

Disclaimer: Vâng, điều này là xấu xa. Đừng bao giờ làm điều đó - đặc biệt là nếu nó sẽ khiến người khác giận bạn.


Mixin. Điều này có thể được kết hợp với T4 để tránh sao chép thủ công ...
Peter Taylor

Như đã lưu ý, điều này gần giống với mixins. Tuy nhiên, bạn đang tiếp cận một khái niệm được gọi là "đặc điểm" và họ sẽ xử lý một cách an toàn những gì bạn đang cố gắng đạt được. Tôi có một mô tả không biết ngôn ngữ tại publius-ovidius.livejournal.com/314737.html Tôi đã tìm kiếm một triển khai rõ ràng cho C #, nhưng chưa thấy một.
Buồng trứng
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.