W bazie danych mojej firmy (aplikacja .NET 3.5) widzę następujący wzór kodu:
bool Foo(int barID, out Baz bazObject) {
try {
// do stuff
bazObject = someResponseObject;
return true;
}
catch (Exception ex) {
// log error
return false;
}
}
// calling code
BazObject baz = new BazObject();
fooObject.Foo(barID, out baz);
if (baz != null) {
// do stuff with baz
}
Staram się owijać wokół głowy, dlaczego miałbyś to zrobić zamiast tego, że Foo
metoda po prostu bierze identyfikator i zwraca Baz
obiekt, zamiast zwracać wartość, która nie jest używana, a faktycznym obiektem jest parametr referencyjny lub wyjściowy.
Czy jest jakaś ukryta zaleta tego stylu kodowania, którego mi brakuje?
c#
code-quality
coding-style
Wayne Molina
źródło
źródło
baz
jestnull
i zwracanybool
istotąfalse
są nie równoważne.new BazObject()
jest nigdynull
, więc jeśli niebazObject
zostanie zaktualizowany przedException
wrzuceniemFoo
,false
to kiedy zostanie zwróconybaz
, nigdy nie będzienull
. To pomaga ogromnie jeśli specyfikacja dlaFoo
były dostępne. W rzeczywistości jest to prawdopodobnie najpoważniejszy problem związany z tym kodem.Odpowiedzi:
Zwykle używasz tego wzorca, aby móc pisać kod w ten sposób:
jest używany na przykład w CLR dla TryGetValue w klasie słownikowej. Pozwala to uniknąć nadmiarowości, ale parametry out i ref zawsze wydawały mi się nieco niechlujne
źródło
Jest to stary kod w stylu C, zanim były wyjątki. Zwracana wartość wskazuje, czy metoda zakończyła się powodzeniem, czy nie, a jeśli tak, parametr zostanie wypełniony wynikiem.
W .net mamy wyjątki w tym celu. Nie powinno być żadnego powodu, aby stosować ten wzór.
[edytuj] Oczywiste są skutki wydajności w obsłudze wyjątków. Może to ma z tym coś wspólnego. Jednak w tym fragmencie kodu jest już zgłaszany wyjątek. Byłoby czystsze pozwolić po prostu przesuwać się w górę stosu, dopóki nie zostanie złapany w bardziej odpowiednim miejscu.
źródło
if (baz.Select())
Ale najczęściej zwracana wartość jest po prostu wyrzucana i wartość jest sprawdzana pod kątem wartości null lub jakiejś właściwości.Biorąc pod uwagę fragment kodu, wygląda to zupełnie bezcelowo. Według mnie początkowy wzorzec kodu sugerowałby, że null dla BazObject byłby dopuszczalnym przypadkiem, a powrót bool jest miarą bezpiecznego określenia przypadku niepowodzenia. Jeśli następujący kod to:
To miałoby dla mnie większy sens, aby zrobić to w ten sposób. Być może jest to metoda, której ktoś wcześniej używał, aby zagwarantować, że baz był przekazywany przez referencję, nie rozumiejąc, jak parametry obiektu faktycznie działają w języku C #.
źródło
Czasami ten wzorzec jest przydatny, gdy osoba dzwoniąca nie powinna dbać o to, czy zwracany typ jest typem referencyjnym czy wartościowym. Jeśli wywołujesz taką metodę w celu pobrania typu wartości, ten typ wartości będzie albo potrzebował ustalonej niepoprawnej wartości (np. Double.NaN), albo potrzebujesz innego sposobu ustalenia sukcesu.
źródło
Pomysł polega na zwróceniu wartości wskazującej, czy proces się powiódł, umożliwiając następujący kod:
Jeśli obiekt nie może mieć wartości NULL (co w twoim przykładzie wygląda poprawnie), lepiej zrobić to w następujący sposób:
Jeśli obiekt może mieć wartość NULL, możliwe są wyjątki:
Jest to powszechny wzorzec używany w C, gdzie nie ma wyjątków. Pozwala to funkcji zwrócić błąd. Wyjątki są ogólnie o wiele czystszym rozwiązaniem.
źródło