Ưu điểm khi sử dụng phương pháp tĩnh riêng


209

Khi tạo một lớp có các phương thức riêng bên trong, thường để giảm trùng lặp mã, không yêu cầu sử dụng bất kỳ trường đối tượng nào, có lợi thế về hiệu năng hoặc bộ nhớ để khai báo phương thức là tĩnh không?

Thí dụ:

foreach (XmlElement element in xmlDoc.DocumentElement.SelectNodes("sample"))
{
    string first = GetInnerXml(element, ".//first");
    string second = GetInnerXml(element, ".//second");
    string third = GetInnerXml(element, ".//third");
}

...

private static string GetInnerXml(XmlElement element, string nodeName)
{
    return GetInnerXml(element, nodeName, null);
}

private static string GetInnerXml(XmlElement element, string nodeName, string defaultValue)
{
    XmlNode node = element.SelectSingleNode(nodeName);
    return node == null ? defaultValue : node.InnerXml;
}

Có bất kỳ lợi thế nào khi khai báo các phương thức GetInnerXml () là tĩnh không? Không có ý kiến ​​trả lời xin vui lòng, tôi có một ý kiến.


Câu trả lời:


221

Từ trang quy tắc FxCop về điều này:

Sau khi bạn đánh dấu các phương thức 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. Phát ra các trang web cuộc gọi không ảo sẽ ngăn kiểm tra trong thời gian chạy cho mỗi cuộc gọi để đảm bảo rằng con trỏ đối tượng hiện tại không phải là null. Điều này có thể dẫn đến tăng hiệu suất có thể đo được cho mã nhạy cảm 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.


37
Tôi cũng sẽ thêm rằng một mệnh đề "tĩnh" không gây hại và đã cung cấp một số "tài liệu" với 1 từ. Nó cho bạn biết rằng phương pháp này không sử dụng bất kỳ thành viên cá thể nào và bạn nhận được tài liệu này gần như miễn phí
frandevel

20
Tôi đã đi xa như nói: "Nếu một phương thức không cần truy cập trạng thái (cái này), hãy làm cho nó tĩnh" như một quy tắc chung.
DanMan

3
Vì lợi ích của sự cân bằng, đáng để chỉ ra rằng nhiều người thường chống lại các phương pháp tĩnh vì chúng phá vỡ tính đa hình, và có nghĩa là đối tượng không thể được đặt ra để thử nghiệm. ví dụ: xem googletesting.blogspot.co.uk/2008/12/ từ
Andy

@ Andy - Điểm tốt. Một cách để vẽ đường thẳng là xem xét phương thức tĩnh có truy cập bất cứ thứ gì bên ngoài các tham số mà bạn truyền vào hay không. Miễn là nó được khép kín theo cách này, nó sẽ dễ kiểm tra và không cần để sơ khai bất cứ điều gì.
Neil

4
Nhiều nhà phát triển không quen thuộc với "private static". Tôi đã sử dụng nó trong cơ sở mã chung của nhóm tôi và nó đã dẫn đến sự nhầm lẫn. Đổi lại, nó cung cấp lợi ích rất nhỏ. Chúng tôi có thể chọn giáo dục mọi người trong nhóm, bao gồm tất cả các nhà phát triển trong tương lai duy trì mã, theo ý nghĩa của nó. Nhưng lợi ích của việc chuyển đổi một phương thức riêng tư sang một tĩnh riêng là rất nhỏ (tức là loại bỏ sự phụ thuộc vào dữ liệu cá thể), nó không đáng để bỏ công sức và nhầm lẫn. Phương thức này là phạm vi riêng tư. Đó là một vấn đề ngôn ngữ không thực sự cần thiết để biết.
Curtis Yallop

93

Khi tôi viết một lớp, hầu hết các phương thức đều thuộc hai loại:

  • Các phương thức sử dụng / thay đổi trạng thái của thể hiện tại.
  • Các phương thức trợ giúp không sử dụng / thay đổi trạng thái của đối tượng hiện tại, nhưng giúp tôi tính toán các giá trị tôi cần ở nơi khác.

Các phương thức tĩnh rất hữu ích, vì chỉ cần nhìn vào chữ ký của nó, bạn biết rằng cách gọi nó không sử dụng hoặc sửa đổi trạng thái của thể hiện hiện tại.

Lấy ví dụ này:

Thư viện lớp học công cộng
{
    Sách tĩnh Tìm sách (Danh sách <Sách> sách, tiêu đề chuỗi)
    {
        // mã ở đây
    }
}

Nếu một ví dụ về trạng thái của thư viện đã bị làm hỏng và tôi đang cố gắng tìm hiểu tại sao, tôi có thể loại trừ findBook là thủ phạm, chỉ từ chữ ký của nó.

Tôi cố gắng giao tiếp nhiều nhất có thể với chữ ký của một phương thức hoặc hàm và đây là một cách tuyệt vời để làm điều đó.


1
Loại khai báo phương thức const trong C ++, phải không?
anhoppe 18/03/2016

Có - đó là một cách tốt khác để sử dụng ngôn ngữ để đơn giản hóa mọi thứ bằng cách hạn chế những gì có thể sai.
Neil

Điều này không nhất thiết đúng. Giả sử rằng một Librarycó một instance field List<Book> _booksđể lưu trữ sách của nó (không phải là cách bạn muốn thiết kế một Librarylớp lẽ nhưng w / e), và nó đi danh sách này để findBook, và rằng các cuộc gọi phương thức tĩnh books.Clear()hay books.Reverse()và vân vân. Nếu bạn cấp quyền truy cập phương thức tĩnh vào một tham chiếu đến một số trạng thái có thể thay đổi, thì phương thức tĩnh đó rất có thể làm rối loạn trạng thái của bạn.
sara

1
Thật. Và trong trường hợp đó, chữ ký sẽ cho chúng ta thấy rằng phương thức này có quyền truy cập (và khả năng biến đổi) một thể hiện của Thư viện.
Neil

Đối với hầu như bất kỳ cấu trúc bảo vệ nào chúng ta có thể sử dụng, có một số cách để làm suy yếu nó. Nhưng sử dụng chúng vẫn là khôn ngoan và giúp thúc đẩy chúng ta đi đúng hướng, hướng tới "hố thành công".
Neil

81

Một cuộc gọi đến một phương thức tĩnh tạo ra một lệnh gọi bằng ngôn ngữ trung gian của Microsoft (MSIL), trong khi đó một cuộc gọi đến một phương thức cá thể tạo ra một lệnh gọi, cũng kiểm tra các tham chiếu đối tượng null. Tuy nhiên, hầu hết thời gian sự khác biệt hiệu suất giữa hai là không đáng kể.

src: MSDN - http://msdn.microsoft.com/en-us/l Library / 79b3xss3 (v = vs.110) .aspx


15

Có, trình biên dịch không cần truyền thiscon trỏ ẩn cho staticcác phương thức. Ngay cả khi bạn không sử dụng nó trong phương thức cá thể của mình, nó vẫn được thông qua.


Làm thế nào điều này liên quan đến một lợi thế hiệu suất hoặc bộ nhớ trong thời gian chạy?
Scott Dorman

11
Truyền một tham số phụ có nghĩa là CPU phải thực hiện thêm công việc để đặt tham số đó vào một thanh ghi và đẩy nó lên ngăn xếp nếu phương thức cá thể gọi ra một phương thức khác.
Kent Boogaart

5

Sẽ nhanh hơn một chút vì không có thông số này được thông qua (mặc dù chi phí hiệu năng của việc gọi phương thức có thể cao hơn đáng kể so với việc tiết kiệm này).

Tôi muốn nói lý do tốt nhất tôi có thể nghĩ đến cho các phương thức tĩnh riêng là nó có nghĩa là bạn không thể vô tình thay đổi đối tượng (vì không có con trỏ này).


4

Điều này buộc bạn phải nhớ cũng khai báo bất kỳ thành viên nào trong phạm vi lớp mà hàm cũng sử dụng dưới dạng tĩnh, điều này sẽ tiết kiệm bộ nhớ tạo các mục đó cho mỗi trường hợp.


Chỉ vì đó là một biến có phạm vi lớp không có nghĩa là nó phải tĩnh.
Scott Dorman

3
Không, nhưng nếu nó được sử dụng bởi một phương thức tĩnh thì nó PHẢI là tĩnh. Nếu phương thức không tĩnh thì có thể bạn đã không làm cho thành viên lớp tĩnh và điều đó sẽ dẫn đến nhiều bộ nhớ được sử dụng cho mỗi phiên bản của lớp.
Joel Coehoorn

2

Tôi rất thích tất cả các phương thức riêng tư là tĩnh trừ khi chúng thực sự không thể. Tôi rất thích những điều sau đây:

public class MyClass
{
    private readonly MyDependency _dependency;

    public MyClass(MyDependency dependency)
    {
        _dependency = dependency;
    }

    public int CalculateHardStuff()
    {
        var intermediate = StepOne(_dependency);
        return StepTwo(intermediate);
    }

    private static int StepOne(MyDependency dependency)
    {
        return dependency.GetFirst3Primes().Sum();
    }

    private static int StepTwo(int intermediate)
    {
        return (intermediate + 5)/4;
    }
}

public class MyDependency
{
    public IEnumerable<int> GetFirst3Primes()
    {
        yield return 2;
        yield return 3;
        yield return 5;
    }
}

trên mọi phương thức truy cập vào trường thể hiện. Tại sao lại thế này? Bởi vì quá trình tính toán này trở nên phức tạp hơn và lớp học kết thúc với 15 phương thức trợ giúp riêng, nên tôi THỰC SỰ muốn có thể kéo chúng ra một lớp mới gói gọn một tập hợp các bước theo cách có ý nghĩa về mặt ngữ nghĩa.

Khi MyClassnhận được nhiều phụ thuộc hơn vì chúng tôi cần đăng nhập và cũng cần thông báo cho một dịch vụ web (vui lòng loại trừ các ví dụ sáo rỗng), thì thực sự hữu ích để dễ dàng xem phương pháp nào có phụ thuộc.

Các công cụ như R # cho phép bạn trích xuất một lớp từ một tập hợp các phương thức tĩnh riêng tư trong một vài lần nhấn phím. Hãy thử làm điều đó khi tất cả các phương thức trợ giúp riêng được liên kết chặt chẽ với trường cá thể và bạn sẽ thấy nó có thể khá đau đầu.


-3

Như đã được nêu, có nhiều lợi thế cho các phương thức tĩnh. Tuy nhiên; hãy nhớ rằng họ sẽ sống trong đống cho cuộc sống của ứng dụng. Gần đây tôi đã dành một ngày để theo dõi rò rỉ bộ nhớ trong Dịch vụ Windows ... rò rỉ là do các phương thức tĩnh riêng bên trong một lớp đã triển khai IDis Dùng và được gọi liên tục từ một câu lệnh sử dụng. Mỗi khi lớp này được tạo, bộ nhớ được dành riêng cho heap cho các phương thức tĩnh trong lớp, thật không may, khi lớp bị loại bỏ, bộ nhớ cho các phương thức tĩnh không được giải phóng. Điều này khiến cho dung lượng bộ nhớ của dịch vụ này tiêu thụ bộ nhớ khả dụng của máy chủ trong một vài ngày với kết quả có thể dự đoán được.


4
Điều này không có ý nghĩa gì. Heap không bao giờ lưu trữ bộ nhớ cho mã cho bất kỳ phương thức nào , tĩnh hay cách khác. Heap là cho các trường hợp đối tượng. Sẽ có dữ liệu trên ngăn xếp cho bất kỳ lời gọi nào của bất kỳ phương thức nào (để giữ bộ nhớ cho các tham số, giá trị trả về, các địa phương không được nâng, v.v.) nhưng tất cả điều đó sẽ biến mất khi phương thức kết thúc thực thi.
Phục vụ
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.