2011-02-01 19 views
12

Tôi có một đoạn mã như sau:Khi nào chính xác để tạo một phương pháp mở rộng?

public class ActivityHelper 
{ 
    public void SetDate(IList<Activity> anActivityList) 
    { 
     foreach(Activity current in anActivityList) 
     { 
      current.Date = DateTime.Now; 
     } 
    } 
    //More methods, properties, fields, etc... 
} 

Điều này có thể dễ dàng được chuyển đổi sang một phương pháp mở rộng. Ví dụ:

public static void SetDate(this IList<Activity> aList) 
{ 
    foreach(Activity current in anActivityList) 
    { 
     current.Date = DateTime.Now; 
    } 
} 

Chức năng ban đầu không sử dụng bất kỳ dữ liệu cụ thể hoặc phương pháp nào từ lớp ActivityHelper làm cho nó có vẻ không đúng. Đây có phải là thời điểm chính xác để viết một phương pháp mở rộng không? Các kịch bản chính xác để tạo phương pháp mở rộng là gì?

+1

Dường như bạn đang đặt câu hỏi sai. Cho dù bạn làm cho nó một phương pháp mở rộng hay không là phần lớn không quan trọng. Nhưng bạn gần như chắc chắn sẽ làm cho nó một phương pháp ** tĩnh ** một trong hai cách. Phương thức đầu tiên của bạn là không tĩnh mặc dù không sử dụng thành viên cá thể nào; đây là một (nhỏ) thiết kế faux-pas. – Timwi

+0

@Timwi Có, tôi rất có thể làm cho phương pháp đó tĩnh và không có lý do cụ thể tại sao tôi không có trong ví dụ này. Trong cả hai trường hợp, tôi vẫn cảm thấy nó là một phương pháp khó xử. – brainimus

+0

Tôi tìm các phương thức mở rộng được sử dụng tốt nhất khi hội đồng hoặc lớp đích được "đóng để cập nhật". Tôi cũng tìm thấy những người sử dụng sai các phương pháp mở rộng để có được nguyên tắc về trách nhiệm duy nhất (SRP). Theo tôi, các lớp tĩnh và các phương thức mở rộng là những khả năng bị sử dụng nhiều nhất. –

Trả lời

12

Brad Adams đã viết về extension method design guidelines:

xem xét sử dụng phương pháp khuyến nông trong bất kỳ tình huống sau đây:

  • Để cung cấp chức năng helper có liên quan đến từng thực hiện một giao diện, nếu nói chức năng có thể được viết theo giao diện cốt lõi. Điều này là do việc triển khai cụ thể không thể được gán cho các giao diện. Ví dụ, các toán tử LINQ to Objects được triển khai như các phương thức mở rộng cho tất cả các kiểu IEnumerable. Do đó, mọi triển khai thực hiện <> của IEnumerable sẽ tự động được bật LINQ.

  • Khi phương pháp thể hiện sẽ giới thiệu phụ thuộc vào một số loại, nhưng phụ thuộc như vậy sẽ phá vỡ các quy tắc quản lý phụ thuộc. Ví dụ, một phụ thuộc từ String vào System.Uri có lẽ không phải là mong muốn, và vì vậy String.ToUri() thể hiện phương thức trả về System.Uri sẽ là thiết kế sai từ một quan điểm quản lý phụ thuộc. Một phương pháp mở rộng tĩnh Uri.ToUri (chuỗi này str) trở về System.Uri sẽ là một thiết kế tốt hơn nhiều.

6

Tôi nghĩ rằng phương pháp mở rộng chỉ thích hợp nếu có một lý do thuyết phục để làm cho phương pháp một phương pháp mở rộng.

Nếu loại là loại bạn không kiểm soát và phương pháp có vẻ không thể tách rời với loại hoặc nếu có lý do thuyết phục để không đặt phương thức trực tiếp vào loại (chẳng hạn như tạo phụ thuộc không mong muốn) thì một phương pháp mở rộng có thể thích hợp.

Cá nhân, nếu kỳ vọng của người dùng API của bạn sẽ là sử dụng lớp "ActivityHelper" khi làm việc với các bộ sưu tập Hoạt động thì có thể tôi sẽ không tạo phương thức tiện ích mở rộng cho việc này. Một phương pháp tiêu chuẩn, không mở rộng sẽ thực sự là một API đơn giản hơn, vì nó dễ hiểu và dễ khám phá. Các phương thức mở rộng khó hiểu từ quan điểm sử dụng - bạn đang gọi một phương thức "trông giống như" nó tồn tại ở đâu đó khác với nơi nó thực sự tồn tại. Trong khi điều này có thể đơn giản hóa cú pháp, nó làm giảm khả năng bảo trì và khả năng phát hiện.

+2

Đúng trên khả năng khám phá. Nếu bạn không biết rằng phương thức mở rộng tồn tại, bạn sẽ không bao giờ tìm thấy nó - không xuất hiện trong intellisense trừ khi bạn đã bao gồm không gian tên chính xác. –

+1

@Kirk: Vâng, và ngay cả khi bạn biết nó 'tồn tại ở đâu đó', việc tìm tài liệu, v.v ... có thể khó khăn trừ khi bạn biết nó đến từ đâu ... –

0

Tôi cũng thường tạo các phương pháp mở rộng để giúp tôi viết mã có dòng chảy mượt mà. Nó thường phụ thuộc vào phương pháp bạn đang tạo.

Nếu bạn cảm thấy rằng phương pháp nên đã có trong khung công tác và quá chung chung thì không sao để tạo ra một phương pháp mở rộng cho điều đó.

Nhưng trước tiên bạn cần phân tích rằng lớp bạn đang mở rộng sẽ luôn ở trạng thái mà phương thức tiện ích của bạn có thể xử lý.

Đối với Hướng dẫn vào đây để Điều Brad

http://blogs.msdn.com/b/brada/archive/2009/01/12/framework-design-guidelines-extension-methods.aspx

4

Trong phương pháp khuyến nông kinh nghiệm của tôi làm việc tốt nhất khi họ:

  • Không có tác dụng phụ (hầu hết các phương pháp khuyến nông đội của tôi đã viết có tác dụng phụ, chúng tôi đã kết thúc việc xóa vì chúng gây ra nhiều vấn đề hơn là họ đã giúp)
  • Chức năng cung cấp áp dụng cho mọi trường hợp hoặc giá trị có thể có của loại chúng đang mở rộng. (Một lần nữa trích dẫn một ví dụ từ nhóm của tôi, string.NormalizeUrl() là không thích hợp vì không phải tất cả các chuỗi đều là URL ngay cả)
+0

Không chắc chắn về cái đầu tiên, LINQ có rất nhiều mặt hiệu ứng. Tôi đồng ý rằng các nhà phát triển có thể có khuynh hướng soạn thảo các tuyên bố và bỏ qua các thực hành mã hóa an toàn, nhưng rõ ràng một người cần biết về các tác dụng phụ. –

+0

Điều này không thực sự đáp ứng với câu hỏi trung tâm về việc liệu người ta có nên sử dụng một phương pháp mở rộng hoặc một phương pháp thông thường trong lớp "Người trợ giúp" hay không. –

+0

Câu hỏi thứ hai mà OP hỏi là có tính chất tổng quát hơn. Tôi tưởng tượng đây là những gì Rex đang trả lời, và tôi chỉ đơn giản là đưa ra một nhận xét. –

0

Về bản chất, Các phương pháp mở rộng cung cấp cú pháp kiểu thông thạo hơn cho các phương thức Trợ giúp. Điều này chuyển thành khả năng dường như thêm chức năng cho các loại hoặc tất cả các triển khai giao diện.

Tuy nhiên, tôi thường tránh xa việc tuyên bố Phương pháp mở rộng có một cú pháp kiểu dáng thông minh, cho phép bạn soạn báo cáo, bị từ chối khi phương thức được đề cập không trả về bất kỳ điều gì.

Tuy nhiên, tôi đoán có thể thuận tiện để các phương pháp của bạn được nhận bởi IntelliSense ... :-)

Các vấn đề liên quan