Phương pháp có thể được thực hiện tĩnh, nhưng nó nên?


366

Chia sẻ lại thích chỉ ra nhiều chức năng trên mỗi trang asp.net có thể được thực hiện tĩnh. Nó có giúp tôi không nếu tôi làm cho chúng tĩnh? Tôi có nên làm cho chúng tĩnh và chuyển chúng đến một lớp tiện ích không?


20
Không phải Resharper thực sự hét lên "sự gắn kết thấp, sự gắn kết thấp"? đã đến lúc xem xét nếu phương thức thực sự thuộc về lớp đó.
PK

Câu trả lời:


245

Các phương thức tĩnh so với các phương thức Instance
10.2.5 Các thành viên tĩnh và cá thể của Đặc tả ngôn ngữ C # giải thích sự khác biệt. Nói chung, các phương thức tĩnh có thể cung cấp một cải tiến hiệu suất rất nhỏ so với các phương thức cá thể, nhưng chỉ trong các tình huống hơi cực đoan (xem câu trả lời này để biết thêm chi tiết về điều đó).

Quy tắc CA1822 trong trạng thái Phân tích mã hoặc FxCop:

"Sau khi [đánh dấu thành viên là tĩnh], trình biên dịch sẽ phát ra các trang web cuộc gọi không ảo đến các thành viên này, điều này sẽ ngăn kiểm tra trong thời gian chạy cho mỗi cuộc gọi để đảm bảo con trỏ đối tượng hiện tại không có giá trị. Điều này có thể đạt được hiệu suất có thể đo được đối với mã nhạy cảm với hiệu năng. Trong một số trường hợp, việc không truy cập được đối tượng hiện tại thể hiện vấn đề chính xác. "

Lớp tiện ích
Bạn không nên chuyển chúng sang lớp tiện ích trừ khi nó có ý nghĩa trong thiết kế của bạn. Nếu phương thức tĩnh liên quan đến một loại cụ thể, như ToRadians(double degrees)phương thức liên quan đến một lớp biểu thị các góc, thì có nghĩa là phương thức đó tồn tại như một thành viên tĩnh của loại đó (lưu ý, đây là một ví dụ phức tạp cho mục đích trình diễn).


2
> trình biên dịch sẽ phát ra các trang web cuộc gọi không ảo cho các thành viên này Trên thực tế đó là "trình biên dịch có thể phát ra ...". Tôi nhớ vài thứ về trình biên dịch C # bằng cách sử dụng callvirt thay vì gọi để khắc phục một số lỗi tiềm ẩn.
Jonathan Allen

24
Tôi cắt và dán nó trực tiếp từ FxCop 1.36. Nếu FxCop sai, đủ công bằng.
Jeff Yates

5
@Maxim Không chắc chắn tôi đánh giá cao tuyên bố "nhảm nhí"; cách khá thô lỗ để tiếp cận người lạ. Tuy nhiên, điểm cơ bản là hợp lệ; Tôi đã cập nhật mọi thứ một chút (cách đây 9 năm, vì vậy tôi không nhớ lại nền tảng của yêu cầu ban đầu của mình).
Jeff Yates

10
@Maxim Quan điểm của bạn không hợp lệ. Tôi đảm bảo với bạn rằng tôi đã không có một đánh giá tốt 9 năm trước. Tôi đánh giá cao những bình luận chỉ ra những sai lầm (hoặc chỉnh sửa sửa lỗi), nhưng đừng thô lỗ cũng như không đặt kỳ vọng vô lý vào người khác. Đừng gọi một cái gì đó là "nhảm nhí"; nó ngụ ý một ý định lừa dối hơn là trung thực với lỗi lầm hay sự thiếu hiểu biết. Nó là bất lịch sự. Tôi tình nguyện dành thời gian của mình để giúp đỡ ở đây và nó thực sự cảm thấy vô nghĩa khi nó bị đối xử thiếu tôn trọng. Đừng nói với tôi những gì bị xúc phạm - đó là lựa chọn của tôi, không phải của bạn. Tìm hiểu làm thế nào để làm cho quan điểm của bạn với sự tôn trọng và tính toàn vẹn. Cảm ơn bạn.
Jeff Yates

2
@Maxim Mặc dù các đại biểu không được lưu trữ bên cạnh mỗi phiên bản, mỗi phiên bản của một lớp không trạng thái thực sự chiếm một số bộ nhớ trên heap, vốn là vô dụng. Thông thường các dịch vụ khởi tạo không phải là đường dẫn nóng trong một ứng dụng, nhưng nếu ứng dụng của bạn kết thúc việc xây dựng nhiều đối tượng này, thì nó sẽ tạo ra áp lực GC có thể tránh được bằng cách sử dụng các phương thức tĩnh. Khiếu nại ban đầu của OP, trong các tình huống cực đoan, các phương thức tĩnh cung cấp lợi ích hiệu suất so với các trường hợp không trạng thái, có sắc thái phù hợp và hợp lệ.
Asad Saeeduddin

259

Hiệu suất, ô nhiễm không gian tên, vv đều là thứ yếu trong quan điểm của tôi. Hãy tự hỏi điều gì là hợp lý. Là phương thức hoạt động hợp lý trên một thể hiện của loại, hoặc nó có liên quan đến chính loại đó không? Nếu nó là cái sau, hãy biến nó thành một phương thức tĩnh. Chỉ di chuyển nó vào một lớp tiện ích nếu nó liên quan đến một loại không thuộc quyền kiểm soát của bạn.

Đôi khi, có những phương thức hoạt động hợp lý trên một cá thể nhưng chưa sử dụng bất kỳ trạng thái nào của cá thể đó . Ví dụ: nếu bạn đang xây dựng một hệ thống tệp và bạn có khái niệm về một thư mục, nhưng bạn chưa triển khai nó, bạn có thể viết một thuộc tính trả về loại đối tượng hệ thống tệp và nó sẽ luôn chỉ là "tập tin" - nhưng nó liên quan về mặt logic với thể hiện và do đó nên là một phương thức cá thể. Điều này cũng quan trọng nếu bạn muốn làm cho phương thức trở nên ảo - việc triển khai cụ thể của bạn có thể không cần trạng thái, nhưng các lớp dẫn xuất có thể. (Ví dụ: hỏi bộ sưu tập xem nó có chỉ đọc hay không - bạn có thể chưa triển khai một hình thức chỉ đọc của bộ sưu tập đó, nhưng rõ ràng đó là một thuộc tính của chính bộ sưu tập, không phải là loại.)


1
Tôi nghĩ rằng một kẻ nói dối giỏi nên có một tùy chọn để hạn chế thông điệp đối với các phương thức không ảo, vì nó sẽ rất phổ biến đối với một phương thức lớp cơ sở thực tế không làm gì cả. Các phương thức ghi đè thường sẽ làm một cái gì đó, nhưng không phải luôn luôn. Đôi khi thật hữu ích khi có một lớp cho một cái gì đó giống như một iEnumerable trống rỗng, có các phương thức chủ yếu bỏ qua thể hiện, nhưng trong trường hợp đó là bắt buộc để chọn đúng phương thức để sử dụng.
supercat

2
"Đôi khi, có những phương thức hoạt động hợp lý trên một cá thể nhưng chưa sử dụng bất kỳ trạng thái nào của cá thể. Ví dụ" Tôi rất thích cách sử dụng "ví dụ" của bạn trong trường hợp này.
PaulBinder

56

Việc đánh dấu một phương thức như statictrong một lớp làm cho nó rõ ràng rằng nó không sử dụng bất kỳ thành viên thể hiện nào, điều này có thể hữu ích để biết khi lướt qua mã.

Bạn không nhất thiết phải chuyển nó sang một lớp khác trừ khi nó được chia sẻ bởi một lớp khác có liên quan chặt chẽ, khôn ngoan.


22

Tôi chắc chắn điều này không xảy ra trong trường hợp của bạn, nhưng một "mùi hôi" mà tôi đã thấy trong một số mã tôi đã phải chịu đựng thông qua việc duy trì sử dụng rất nhiều phương pháp tĩnh.

Thật không may, chúng là các phương thức tĩnh giả định một trạng thái ứng dụng cụ thể. (tại sao chắc chắn, chúng ta sẽ chỉ có một người dùng cho mỗi ứng dụng! Tại sao lớp Người dùng không theo dõi điều đó trong các biến tĩnh?) Chúng là những cách tuyệt vời để truy cập các biến toàn cục. Họ cũng có các hàm tạo tĩnh (!), Gần như luôn là một ý tưởng tồi. (Tôi biết có một vài trường hợp ngoại lệ hợp lý).

Tuy nhiên, các phương thức tĩnh khá hữu ích khi chúng đưa ra logic miền không thực sự phụ thuộc vào trạng thái của một thể hiện của đối tượng. Họ có thể làm cho mã của bạn dễ đọc hơn rất nhiều.

Chỉ cần chắc chắn rằng bạn đang đặt chúng ở đúng nơi. Là các phương thức tĩnh thao túng trạng thái bên trong của các đối tượng khác? Một trường hợp tốt có thể được thực hiện rằng hành vi của họ thuộc về một trong những lớp thay thế? Nếu bạn không tách biệt mối quan tâm đúng cách, bạn có thể bị đau đầu sau này.


4
Vấn đề của bạn là với các trường / thuộc tính tĩnh, không phải phương thức tĩnh.
Asad Saeeduddin

10

Đây là đọc thú vị:

http://thecinatingledge.com/?p=57

ReSharper không thực sự đề nghị bạn làm cho phương thức của bạn tĩnh. Bạn nên tự hỏi tại sao phương thức đó lại nằm trong lớp đó chứ không phải là một trong những lớp xuất hiện trong chữ ký của nó ...

nhưng đây là những gì tài liệu chia sẻ lại nói: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+ADE+static


2
Tôi nghĩ rằng điểm này được đánh giá thấp. Điều mà công cụ thực sự nói với bạn là phương thức này chỉ hoạt động trên một số thành viên của lớp khác. Nếu đó là một loại đối tượng lệnh (hoặc "ca sử dụng" hoặc "tương tác"), thì trách nhiệm của ai là thao túng các đối tượng khác, điều đó tốt. Tuy nhiên, nếu nó chỉ thao túng một lớp khác nghe có vẻ giống như Feature Envy .
Greg

9

Chỉ cần thêm vào câu trả lời của @Jason True , điều quan trọng là phải nhận ra rằng chỉ cần đặt 'tĩnh' vào một phương thức không đảm bảo rằng phương thức đó sẽ là 'thuần túy'. Nó sẽ không trạng thái đối với lớp được khai báo, nhưng nó cũng có thể truy cập vào các đối tượng 'tĩnh' khác có trạng thái (cấu hình ứng dụng, v.v.), điều này có thể không phải luôn luôn là một điều xấu, nhưng một trong những lý do là Cá nhân tôi có xu hướng thích các phương thức tĩnh khi tôi có thể là nếu chúng thuần túy, bạn có thể kiểm tra và suy luận về chúng một cách cô lập, mà không phải lo lắng về trạng thái xung quanh.


6

Bạn nên làm những gì dễ đọc và trực quan nhất trong một kịch bản nhất định.

Đối số hiệu năng không phải là một đối số tốt ngoại trừ trong các tình huống cực đoan nhất vì điều duy nhất đang thực sự xảy ra là một tham số phụ ( this) đang được đẩy lên ngăn xếp cho các phương thức ví dụ.


6

Đối với logic phức tạp trong một lớp, tôi đã thấy các phương thức tĩnh riêng hữu ích trong việc tạo logic tách biệt, trong đó các đầu vào cá thể được xác định rõ ràng trong chữ ký phương thức và không có tác dụng phụ nào có thể xảy ra. Tất cả các đầu ra phải thông qua giá trị trả về hoặc tham số out / ref. Việc chia logic phức tạp thành các khối mã khônghiệu ứng phụ có thể cải thiện khả năng đọc của mã và sự tự tin của nhóm phát triển về nó.

Mặt khác, nó có thể dẫn đến một lớp bị ô nhiễm bởi sự phổ biến của các phương thức tiện ích. Như thường lệ, việc đặt tên logic, tài liệu và áp dụng nhất quán các quy ước mã hóa nhóm có thể làm giảm bớt điều này.


5

ReSharper không kiểm tra logic. Nó chỉ kiểm tra xem phương thức có sử dụng các thành viên thể hiện hay không. Nếu phương thức này là riêng tư và chỉ được gọi bởi (có thể chỉ một) phương thức cá thể thì đây là một dấu hiệu để cho nó một phương thức cá thể.


3

Nếu các chức năng được chia sẻ trên nhiều trang, bạn cũng có thể đặt chúng vào một lớp trang cơ sở và sau đó có tất cả các trang asp.net sử dụng chức năng đó được kế thừa từ nó (và các chức năng vẫn có thể tĩnh).


3

Làm cho một phương thức tĩnh có nghĩa là bạn có thể gọi phương thức từ bên ngoài lớp mà không cần tạo một thể hiện của lớp đó trước. Điều này hữu ích khi làm việc với các đối tượng nhà cung cấp bên thứ ba hoặc các tiện ích bổ sung. Hãy tưởng tượng nếu trước tiên bạn phải tạo một đối tượng Console "con" trước khi gọi con.Writeline ();


Java sẽ yêu cầu bạn tạo một cá thể xuất xưởng để tạo đối tượng Console trước khi gọi con.Writeline ().
ScottMichaud

2

Nó giúp kiểm soát ô nhiễm không gian tên.


8
Làm thế nào để thực hiện một phương thức tĩnh giúp tránh ô nhiễm không gian tên?
lockstock

1
Từ kinh nghiệm, bằng cách nhóm các phương thức vào các lớp bằng các phương thức tĩnh, bạn sẽ tránh được trải nghiệm phải có tiền tố tất cả các "túi lấy" các hàm lỏng lẻo có thể xung đột với các hàm thư viện hoặc hàm dựng sẵn khác. Với các phương thức tĩnh, chúng được đặt tên một cách hiệu quả dưới Tên lớp, ví dụ: Class.a_core_function( .. )vsa_core_function( .. )
lintuxvi 8/12/2016

0

Chỉ cần tuppence của tôi: Thêm tất cả các phương thức tĩnh được chia sẻ vào một lớp tiện ích cho phép bạn thêm

using static className; 

để sử dụng các câu lệnh của bạn, làm cho mã nhanh hơn để gõ và dễ đọc hơn. Ví dụ, tôi có một số lượng lớn cái được gọi là "biến toàn cục" trong một số mã tôi được thừa hưởng. Thay vì tạo các biến toàn cục trong một lớp là một lớp thể hiện, tôi đặt tất cả chúng là các thuộc tính tĩnh của một lớp toàn cầu. Nó thực hiện công việc, nếu lộn xộn và tôi chỉ có thể tham chiếu các thuộc tính theo tên vì tôi có không gian tên tĩnh đã được tham chiếu.

Tôi không biết đây có phải là thực hành tốt hay không. Tôi có rất nhiều điều để tìm hiểu về C # 4/5 và rất nhiều mã kế thừa để tái cấu trúc đến mức tôi chỉ cố gắng để các mẹo Roselyn hướng dẫn cho tôi.

Joey


0

Tôi hy vọng, bạn đã hiểu sự khác biệt giữa các phương thức tĩnh và cá thể. Ngoài ra, có thể có một câu trả lời dài và một câu trả lời ngắn. Câu trả lời dài đã được cung cấp bởi những người khác.

Câu trả lời ngắn gọn của tôi: Có, bạn có thể chuyển đổi chúng thành các phương thức tĩnh nếu Resharper gợi ý. Không có hại khi làm như vậy. Thay vào đó, bằng cách làm cho phương thức tĩnh, bạn thực sự bảo vệ phương thức sao cho, không cần thiết bạn không trượt bất kỳ thành viên thể hiện nào vào phương thức đó. Theo cách đó, bạn có thể đạt được nguyên tắc OOP " Tối thiểu hóa khả năng truy cập của các lớp và thành viên ".

Khi ReSharper gợi ý rằng một phương thức cá thể có thể được chuyển đổi thành một phương thức tĩnh, nó thực sự nói với bạn, "Tại sao .. phương thức này lại nằm trong lớp này vì nó không thực sự sử dụng bất kỳ trạng thái nào của nó?" Vì vậy, nó cung cấp cho bạn thực phẩm cho suy nghĩ. Sau đó, chính bạn là người có thể nhận ra sự cần thiết phải di chuyển phương thức đó sang một lớp tiện ích tĩnh hay không. Theo các nguyên tắc RẮN, một lớp chỉ nên có một trách nhiệm cốt lõi. Vì vậy, bạn có thể làm sạch tốt hơn các lớp học của bạn theo cách đó. Đôi khi, bạn cần một số phương thức trợ giúp ngay cả trong lớp cá thể của bạn. Nếu đó là trường hợp, bạn có thể giữ họ trong một người trợ giúp #region.

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.