2011-02-01 17 views
12

mam część kodu jak następuje:Kiedy należy utworzyć metodę rozszerzenia?

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

ten może być łatwo przekształca się w sposób wewnętrzny. Na przykład:

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

Oryginalny funkcja nie używa żadnych konkretnych danych lub metody instancji z klasy ActivityHelper co sprawia, że ​​wydaje się, że jest w niewłaściwym miejscu. Czy jest to właściwy czas na napisanie metody rozszerzenia? Jakie są prawidłowe scenariusze tworzenia metod rozszerzenia?

+1

Wydaje się, że pytasz niewłaściwe pytanie. To, czy uczynisz ją metodą rozszerzenia, czy nie, jest w dużej mierze nieważne. Ale powinieneś prawie na pewno uczynić ją metodą ** static ** w obu kierunkach. Twoja pierwsza metoda jest niestatyczna pomimo braku członków instancji; to jest (pomniejszy) projekt faux-pas. – Timwi

+0

@ Timwi Tak, mogłem bardzo dobrze uczynić tę metodę statyczną i nie ma konkretnego powodu, dla którego nie zrobiłem tego w tym przykładzie. W każdym razie nadal uważam, że jest to metoda niezręczna. – brainimus

+0

Metody znajdowania rozszerzeń są najlepiej używane, gdy zespół docelowy lub klasa jest "zamknięta dla aktualizacji". Uważam też, że ludzie niewłaściwie korzystają z metod przedłużania, aby ominąć zasadę odpowiedzialności pojedynczej (SRP - Single Responsibility Principle Principle). Moim zdaniem klasy statyczne i metody rozszerzeń są najbardziej niewłaściwie wykorzystywanymi możliwościami. –

Odpowiedz

12

Brad Adams napisał o extension method design guidelines:

rozważyć użycie metody rozszerzenie w którykolwiek z następujących scenariuszy:

  • celu zapewnienia funkcjonalności pomocnika istotne dla każdego wdrożenia interfejsu, jeśli wspomniana funkcjonalność można napisać w kategoriach podstawowego interfejsu. Dzieje się tak dlatego, że implementacji betonu nie można w inny sposób przypisywać do interfejsów. Na przykład operatory LINQ to Objects są implementowane jako metody rozszerzenia dla wszystkich typów IEnumerable. Zatem dowolna implementacja IEnumerable <> jest automatycznie włączona LINQ.

  • Gdy metoda instancji wprowadziłaby zależność od pewnego typu, ale taka zależność złamałaby reguły zarządzania zależnościami. Na przykład zależność od String do System.Uri prawdopodobnie nie jest pożądana, a więc metoda instancji String.ToUri() zwracająca System.Uri byłaby niewłaściwą konstrukcją z perspektywy zarządzania zależnościami. Metoda statycznej rozbudowy Uri.ToUri (ten ciąg str) zwracająca System.Uri byłaby znacznie lepszym projektem.

6

myślę metody rozszerzeń są tylko właściwe, jeśli istnieje powód, aby metoda metodę rozszerzenia.

Jeśli typem jest ten, nad którym nie masz kontroli, a metoda powinna wydawać się integralna z typem lub jeśli istnieje nieodparty powód, aby nie umieszczać metody bezpośrednio na typie (na przykład tworząc niepożądaną zależność) wtedy odpowiednia może być metoda rozszerzenia.

Osobiście, jeśli oczekiwanie użytkownika interfejsu API będzie już używać klasy "ActivityHelper" podczas pracy z kolekcjami działań, prawdopodobnie nie utworzę dla tego metody rozszerzenia. Standardowa metoda bez rozszerzenia będzie w rzeczywistości prostszym interfejsem API, ponieważ jest łatwo zrozumiała i wykrywalna. Metody rozszerzeń są podchwytliwe z punktu widzenia użycia - nazywasz metodę, która "wygląda tak", że istnieje gdzieś poza tym, gdzie faktycznie istnieje. Chociaż może to uprościć składnię, zmniejsza łatwość obsługi i wykrywalność.

+2

Prawda o wykrywalności. Jeśli nie wiesz, że metoda rozszerzenia istnieje, nigdy jej nie znajdziesz - nie pojawia się w intellisense, chyba że podałeś poprawny obszar nazw. –

+1

@Kirk: Tak, a nawet jeśli wiesz, że "gdzieś istnieje", znalezienie dokumentacji itp. Może być trudne, chyba że wiesz, skąd się bierze ... –

0

Cóż, zwykle tworzę metody rozszerzania, aby pomóc mi pisać kody, które mają płynny przepływ. Zasadniczo zależy to od metody, którą tworzysz.

Jeśli uważasz, że metoda powinna być już w ramach i jest zbyt ogólna, to w porządku, aby utworzyć metodę rozszerzenia dla tego.

Najpierw jednak należy przeanalizować, czy rozszerzana klasa będzie zawsze w stanie, z którą może poradzić sobie metoda rozszerzenia.

Dla wytycznych tutaj do Brada art

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

4

W moich metod rozszerzenie doświadczenia działają najlepiej, gdy:

  • Nie ma skutków ubocznych (większość metod rozszerzenie mojego zespołu napisałem, że mają efekty uboczne, skończyło się usunięcie, ponieważ spowodowało więcej problemów niż im pomogło)
  • Oferuje funkcjonalność, która ma zastosowanie do każdej możliwej instancji lub wartości typ, który rozszerzają. (Ponownie powołując się na przykład z mojego zespołu, string.NormalizeUrl() nie jest właściwe, ponieważ nie wszystkie ciągi są nawet adresy anyway)
+0

Nie jestem pewien co do pierwszego, Linq ma wiele stron- ruchomości. Zgadzam się, że programiści mogą mieć skłonność do komponowania wypowiedzi i pomijania bezpiecznych metod kodowania, ale oczywiście należy zdawać sobie sprawę z efektów ubocznych. –

+0

To nie odpowiada na główne pytanie, czy należy użyć metody rozszerzenia lub zwykłej metody w klasie "Pomocnika". –

+0

Drugie pytanie, o które pytał PO, ma bardziej ogólny charakter. Wyobrażam sobie, na co Rex odpowiada, a ja po prostu robię uwagę. –

0

W istocie, Przedłużacze metody zapewniają bardziej płynny styl składni dla metody pomocnika. Przekłada się to na możliwość pozornego dodawania funkcjonalności do typów lub wszystkich implementacji interfejsów.

Jednak generalnie odbiegam od deklarowania metod rozszerzeń o returntype void, ponieważ uważam, że użyteczność tej płynnej składni stylów, która pozwala na komponowanie instrukcji, jest negowana, gdy dana metoda nie zwraca niczego.

Jednak myślę, że może to być przydatne, aby mieć swoje metody podchwycona przez IntelliSense ... :-)