Pytanie Metody rozszerzania a metody instancji a klasa statyczna [zamknięte]


Jestem trochę zdezorientowany na temat różnych sposobów wykorzystania metod do interakcji z obiektami w języku C #, w szczególności głównych różnic w projektowaniu i następstw między następującymi:

  1. Wywoływanie metody instancji
  2. Używanie klasy statycznej na POCO
  3. Tworzenie metody rozszerzenia

Przykład:

public class MyPoint
{
    public double x { get; set; }
    public double y { get; set; }

    public double? DistanceFrom(MyPoint p)
    {
        if (p != null)
        {
            return  Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));
        }
        return null;
    }
}

Jeśli mógłbyś osiągnąć pożądany rezultat, po prostu umieszczając metodę w definicji klasy, dlaczego preferowałbyś POCO w połączeniu ze statyczną klasą pomocniczą lub metodą rozszerzenia?


12
2018-05-29 18:24


pochodzenie


A jeśli nie masz definicji klasy? Teraz potrzebujesz albo statycznej klasy pomocnika, albo metod rozszerzenia. Metody rozszerzeń umożliwiają rozszerzanie klas nie jesteś właścicielem źródła. Pozwalają również na usunięcie niektórych mniej popularnych funkcji, aby umieścić je gdzie indziej nadal można dostać, jeśli trzeba, ale są domyślnie nie włączone. - 202_accepted
@ Ebrown, Interesujące, nigdy nie myślałem o tym w ten sposób. - johnnyRose
Możesz także zdefiniować metody rozszerzeń na interfejsach. - juharr
To jedna z fajnych rzeczy metod rozszerzania: powiedz, że chcesz rozszerzyć klasę A włączając metodę DoSomethingCooler(), ale definicja klasy A istnieje w przestrzeni nazw EBrown.NamespaceB w oddzielnej bibliotece DLL, do której nie należy kod źródłowy, można zdefiniować metodę rozszerzenia dla klasy A dzięki czemu możesz zadzwonić A.DoSomethingCooler() tak jak gdybyś był właścicielem źródła. Wada: członkowie prywatni są nadal prywatni. - 202_accepted


Odpowiedzi:


Zapytałeś: "Jeśli mógłbyś osiągnąć pożądany rezultat, po prostu umieszczając metodę w definicji klasy, dlaczego preferowałbyś POCO w połączeniu ze statyczną klasą pomocniczą lub metodą rozszerzenia?"

Odpowiedź jest taka, że ​​zależy to od sytuacji i jeśli omawiane metody są bezpośrednio związane z podstawową troską twojej klasy (zob zasada jednej odpowiedzialności).

Oto kilka przykładów, gdzie dobrym pomysłem byłoby użycie każdego rodzaju podejścia / metody (przy użyciu próbki kodu jako punktu wyjścia).

1. Metody instancji

//This all makes sense as instance methods because you're 
//encapsulating logic MyPoint is concerned with.
public class MyPoint
{
    public double x { get; set; }
    public double y { get; set; }

    public double? DistanceFrom(MyPoint p)
    {
        if (p != null)
            return  Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));            
        return null;
    }
}

2. Metody klas statycznych - Przykład zarejestrowania błędu.

    //Your class doesn't directly concern itself with logging implmentation;
    //that's something that is better left to a separate class, perhaps
    //a "Logger" utility class with static methods that are available to your class.
    public double? DistanceFrom(MyPoint p)
    {
        try
        {
            if (p != null)
                return  Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));            
            return null;
        }
        catch(Exception ex)
        {
             //**** Static helper class that can be called from other classes ****
             Logger.LogError(ex);

             //NOTE: Logger might encapsulate other logging methods like...
             //Logger.LogInformation(string s)
             //...so an extension method would be less natural, since Logger
             //doesn't relate to a specific base type that you can create an
             //extension method for.
        }
}

3. Metody rozszerzania - Przykład serializacji XML.

//Maybe you want to make it so that any object can XML serialize itself
//using an easy-to-use, shared syntax.
//Your MyPoint class isn't directly concerned about XML serialization,
//so it doesn't make sense to implement this as an instance method but
//MyPoint can pick up this capability from this extension method.
public static class XmlSerialization
{
    public static string ToXml(this object valueToSerialize)
    {
        var serializer = new XmlSerializer(valueToSerialize.GetType());
        var sb = new StringBuilder();
        using (var writer = new StringWriter(sb))
            serializer.Serialize(writer, valueToSerialize);

        return sb.ToString();
    }
}

//example usage
var point = new MyPoint();
var pointXml = point.ToXml(); //<- from the extension method

Zasada jest taka:

  1. Jeśli metoda odnosi się do głównego problemu klasy, umieść go w metodzie instancji.
  2. Jeśli masz ogólne narzędzie, które może być przydatne dla wielu klas, rozważ umieszczenie go w metodzie klasy statycznej.
  3. Jeśli masz sytuację podobną do 2, ale jest ona związana z pojedynczym typem podstawowym lub uważasz, że kod będzie wyglądał czystszy / bardziej zwięzły bez konieczności oddzielnego odniesienia do klasy statycznej, rozważ metodę rozszerzenia.

14
2018-05-29 18:52



W sumie, myślę, że to najlepsza odpowiedź. Mam problem z twoim przykładem klasy statycznej, ale prawdopodobnie jest to tylko problem z samym przykładem. Jeśli istnieje logika biznesowa lub coś, co nie ma nic wspólnego z Pointsię, to powinno być w osobnej klasie. Oczywiście, jeśli to możliwe, powinna to być metoda rozszerzenia. Statyczne klasy takie jak Helper zajęcia są nadużywane. Niezależnie od tego, czy jest to członek, to tam powinno być (czy to na obiekcie, czy na przedłużeniu). - Kyle W
Pominąłeś this przed pierwszym parametrem w twoim ToXml metoda rozszerzenia. - juharr
Tak, myślę, że klasa statyczna ma przewagę nad metodą rozszerzenia, jeśli odpowiedzialność klasy statycznej nie odnosi się bezpośrednio do określonego typu. W przykładzie "Logger" możesz mieć kilka metod takich jak "Logger.LogError (Exception ex)" i "Logger.LogInformation (komunikat tekstowy)". Metoda rozszerzenia nie jest w tym przypadku naturalną opcją, ponieważ chcesz, aby rejestrator enkapsulował logikę rejestrowania, ale nie ma żadnego naturalnego typu, który można rozszerzyć. - Colin
@juharr - Dzięki! Naprawiłem to zaniedbanie. - Colin
@Colin - Fantastyczna odpowiedź z solidnymi przykładami. Dziękuję Ci! - johnnyRose


Instancje / Metody statyczne

Dostępni członkowie: public, protected, private (nie można uzyskać dostępu, jeśli jest dziedziczone)

Definicja: Ta sama klasa / struct / interface (można podzielić na pliki z rozszerzeniem partial słowo kluczowe)

Zwane jako: object.Method()

W tym kontekście mam na myśli to Metody statyczne są zdefiniowane metody w klasie manipulują. Oznacza to, że są one zdefiniowane wraz z innymi obiektami klasy. (Metody statyczne zdefiniowane w MyPoint klasa w twoim przykładowym kodzie.)

Wszyscy wiemy (lub powinniśmy wiedzieć), jakie one są i jakie są dla nich korzyści, nie będę wchodził w szczegóły, z wyjątkiem tego, że:

Metody instancji mają dostęp do wszystko  private, protected, i public członkowie klasy. Tak jak static metody.

W większości przypadków, jeśli masz dużą liczbę metod i / lub właściwości do dodania, lub one znacznie się zmienić działanie obiektu, powinieneś dziedziczyć oryginalny obiekt (jeśli to możliwe). To daje ci dostęp do wszystkich public i protected członkowie class/struct/interface.

Metody statycznej klasy pomocniczej

Dostępni członkowie: public

Definicja: Dowolna klasa / przestrzeń nazw

Zwane jako: HelperClass.Method(object)

Przez Metody statycznej klasy pomocniczej Sugeruję, że rzeczywista definicja staticmetody, o których mowa w tej sekcji, to nie w rzeczywistej definicji klasy. (Tj. Klasa taka jak MyPointHelpers lub podobne, używając przykładu kodu.)

Metody klasy Static Helper tylko mieć dostęp do public członkowie obiektu (podobnie jak metody Extension, napisałem tę sekcję po sekcji metody rozszerzenia).

Statyczne klasy pomocnicze i metody rozszerzeń są ze sobą ściśle powiązane, aw wielu przypadkach są takie same. Dlatego zostawię im korzyści w sekcji Metody rozszerzeń.

Metody rozszerzeń

Dostępni członkowie: public

Definicja: Dowolna klasa / przestrzeń nazw

Zwane jako: object.Method()

Metody rozszerzenia tylko mieć dostęp do public członkowie obiektu. Chociaż oni zjawić się być członkami klasy, oni są nie. Ogranicza to, do czego są one przydatne. (Metody wymagające dostępu każdy z private lub protected członkowie powinni nie być rozszerzeniami.)

Metody rozszerzenia służą trzem olbrzymi korzyści w mojej opinii.

  1. Powiedz, że rozwijasz klasę Ai klasa A zawiera około 7 metod. Wiesz również, że chciałbyś opracować kilka metod, których nie chcesz zawsze potrzebna, ale byłoby to przydatne, gdybyś kiedykolwiek to zrobił. Możesz użyć do tego metod rozszerzenia. Te metody zostaną usunięte z innej klasy, którą możesz dodać (w klasie, dzięki C # 6.0) później, jeśli będziesz ich potrzebować. Niezwykłe metody, o których wiesz, że chcesz je później użyć, ale wiesz, że nie zawsze są potrzebne.

  2. Powiedz, że rozwijasz program Ai używasz klasy z biblioteki DLL Something.Other.C, że nie jesteś właścicielem źródła. Teraz chcesz dodać metodę, która współdziała z klasą Something.Other.C w taki sposób ma sens z instancją lub zwykłą metodą statyczną, ale nie masz źródła, więc nie możesz! Wprowadź metody rozszerzenia, w których możesz zdefiniować metodę pojawia się być członkiem klasy Something.Other.C, ale jest tak właściwie część Twój kod.

  3. Załóżmy, że tworzymy własną bibliotekę, której używasz z wieloma własnymi aplikacjami, i zdajesz sobie sprawę z tego, że rozwijasz aplikację X że naprawdę można użyć metody Y na zajęciach A jeszcze raz. Cóż, zamiast modyfikować definicję klasy A (bo to o wiele więcej pracy, a ty nie używasz metody Y w dowolnym miejscu z wyjątkiem aplikacji X), możesz zdefiniować metodę rozszerzenia Y, na klasa A to jest tylko obecny w aplikacji X. Teraz Twój koszt metody jest ściśle ograniczony do aplikacji X. Podanie Z nie musi mieć tej metody rozszerzenia.

Wydajność

Jeśli chodzi o wydajność, zależy to od metod, tego, co robią i od tego, jak to robią. Będziesz podlegać cokolwiek public Właściwości / metody / pola dotyczyły obiektów, które modyfikujesz, i musiałyby to sprawdzić. (Jeśli dzwonisz public Value zamiast private value powoduje pewne znaczące narzuty sprawdzania poprawności, metoda instancji ma więcej sensu, ponieważ może pracować z privatepola lub właściwości.)


10
2018-05-29 18:42



"Metody klasy Static Helper mają tylko dostęp do publicznych elementów obiektu" - metody statyczne mają również dostęp do prywatnych elementów typu, w którym są zdefiniowane. Często używane do metod fabrycznych (np. SymmetricAlgorithm.Create(), MySingleton.Instance - Joe
@Joe Gdyby  static metody są zdefiniowane w object's class, to jest. Jeśli są zdefiniowane, powiedzmy, MyPointHelpers to jest fałszywe stwierdzenie. - 202_accepted
@Joe, wyjaśniłem co mam na myśli, kiedy używam tego terminu static w każdym kontekście. - 202_accepted
To jest fantastyczna odpowiedź - żałuję, że nie mogłem jej również zaakceptować. Dziękuję bardzo za wyjaśnienia! - johnnyRose
@Ebrown Mam jeszcze około trzech godzin, zanim będę mógł ponownie przegłosować. Nie martw się jednak - mam zamiar zrobić upust w tej sprawie. - johnnyRose


W skrócie:

  1. Metody instancji
    • Właściwości instancji są jak rzeczowniki. na przykład cat.Color = Color.Blue;
    • Metody instancji są jak czasowniki. Powinny one skutkować działaniem związanym z typem klasy. na przykład cat.Meow();
    • Ten typ metody jest bardzo popularny w języku C #.
  2. Metody statyczne
    • Pomyśl o tym jako o metodzie pomocnika.
    • Metody statyczne zazwyczaj wykonują działanie związane z typem klasy ... a nie określoną instancją.
    • Metody statyczne muszą być zdefiniowane podczas tworzenia klasy.
    • Przykład: File.Open(String, FileMode) to statyczna metoda, która zwraca FileStream. Nie ma potrzeby posiadania instancji plik tutaj.
  3. Metody rozszerzenia
    • Pomyśl o tym jako o metodzie pomocnika.
    • Rozbudowa metody są zdefiniowane po ... istniejących klasach zewnętrznych, których nie można zmienić, ale żałuję, że nie można tego zmienić.
    • Na przykład: często zdarza się, że ludzie piszą metody rozszerzenia dla DateTime klasa.
    • Nierzadko zdarza się debata o tym, kiedy / gdzie powinna być zastosowana metoda rozszerzenia.

REFERENCJE


7
2018-05-29 18:33



Metody rozszerzeń można również wykorzystać do zdefiniowania standardowego zachowania instancji. na przykład System.Linq.Enumerable klasa. - Guvante


Największe różnice to:

  • możesz definiować rozszerzenia obiektów, których nie możesz zmienić
  • metoda instancji może uzyskać dostęp do zmiennych prywatnych, w których statyczne metody / rozszerzenia nie mogą

Metody statyczne i rozszerzenia są zasadniczo takie same: Visual Studio pozwala na wywoływanie metod rozszerzeń jak gdyby były metodą instancji, ale ostatecznie jest to statyczna metoda z przekazaną do niej instancją.

Nie wiem o występie i nie sądzę, żebyś się tym martwił. Być może metody instancji są nieco szybsze, jeśli uzyskasz dostęp do wielu właściwości, ponieważ bieżąca instancja jest już na stosie (ale nie wiem na pewno, czy kompilator działa w ten sposób).

Osobiście dodaję metody do klas, jeśli naprawdę należą one do zachowania tej klasy, i używają metod rozszerzeń do wykonywania operacji o szerszym zakresie, takich jak myClass.ConvertToOtherType().


1
2018-05-29 18:30