2009-09-16 20 views
8

Zarówno w SQL, jak iw C#, nigdy nie lubiłem parametrów wyjściowych. Nigdy też nie przekazałem parametrów ByRef w VB6. Coś o liczeniu na efekty uboczne, aby coś zrobić po prostu przeszkadza mi.Co jest nie tak z parametrami wyjściowymi?

Wiem, że nie są w stanie zwracać wielu wyników z funkcji, ale zestaw wierszy w SQL lub złożony typ danych w C# i VB działa równie dobrze i wydaje mi się bardziej samokomponowany.

Czy jest coś nie tak z moim sposobem myślenia, czy też istnieją zasoby z autorytatywnych źródeł, które wspierają mnie? Jakie jest Twoje osobiste zdanie na ten temat i dlaczego? Co mogę powiedzieć kolegom, którzy chcą zaprojektować parametry wyjściowe, które mogą przekonać ich do korzystania z różnych struktur?

EDYCJA: ciekawy obrót - parametr wyjściowy, z którego zadawałem to pytanie, został użyty zamiast wartości zwracanej. Kiedy zwracana jest wartość "BŁĄD", wywołujący powinien traktować ją jako wyjątek. Robiłem to, ale nie byłem zadowolony z tego pomysłu. Współpracownik nie został poinformowany o potrzebie radzenia sobie z tym stanem iw rezultacie stracono dużo pieniędzy, ponieważ procedura nie przebiegła bezgłośnie!

+1

To jest subiektywne i powinno być wspólnotową wiki dla dalszego istnienia. Zauważam, że jest już jeden bliski traf. Nie zamknę, chyba że nie zaznaczysz tego CW. – Randolpho

+4

Co wiem, ale to brzmi dla mnie jak uczciwe pytanie o kompromisy projektowe. – JeffH

+0

zmieniono znaczniki tak, aby zawierały odniesienia do sql + vb w pytaniach – gbn

Odpowiedz

11

Bob Martin napisał o tym Clean Code. Parametry wyjściowe łamią podstawową ideę funkcji.

output = someMethod(input)

+0

Przechowywany proc nie jest jednak funkcją, ale rozumiem, że rozumowanie – gbn

+0

wygląda jak link do Boba Martina jest już martwy. – PaulBinder

27

Parametry wyjściowe mogą być zapachem kodu wskazującym, że twoja metoda robi zbyt wiele. Jeśli chcesz zwrócić więcej niż jedną wartość, metoda prawdopodobnie wykonuje więcej niż jedną rzecz. Jeśli dane są ściśle powiązane, prawdopodobnie skorzystałaby z klasy, która zawiera obie wartości.

Oczywiście nie jest to ZAWSZE, ale okazało się, że tak jest zazwyczaj.

Innymi słowy, myślę, że masz rację, aby ich unikać.

0

Generalnie nigdy ich nie używam, myślę, że są mylące i zbyt łatwe do nadużywania. Od czasu do czasu używamy parametrów ref, ale ma to więcej wspólnego z przekazywaniem struktur i ich odzyskiwaniem.

0

Twoja opinia brzmi dla mnie rozsądnie.

Inną wadą parametrów wyjściowych jest dodatkowy kod potrzebny do przekazania wyników z jednej funkcji do drugiej. Musisz zadeklarować zmienną (y), wywołać funkcję, aby uzyskać ich wartości, a następnie przekazać te wartości do innej funkcji. Nie można po prostu zagnieżdżać wywołań funkcji. To sprawia, że ​​kod jest czytany bardzo ostrożnie, a nie deklaratywnie.

1

Myślę, że są użyteczne dla uzyskania identyfikatory nowo wstawionych wierszy w tym samym poleceniu SQL, ale nie sądzę, ja używałem ich o wiele więcej.

0

C++ 0x pobiera krotki, anonimowe elementy przypominające strukturę, których członkowie uzyskują dostęp przez indeks. Programiści C++ będą mogli spakować wiele wartości do jednego z nich i zwrócić je. Czy C# ma coś takiego? Czy zamiast tego może zwrócić tablicę? Ale parametry wyjściowe są nieco niezręczne i niejasne.

+0

C# może łatwo zwrócić tablicę. Ale zwrócenie tablicy (która jest w istocie tym, czym jest także krotka) wydaje mi się dość nie-semantyczna i może łatwo się zagmatwać. Jeśli zawsze zwracasz ten sam zestaw wartości, to zmienne wyjściowe wydają mi się lepszym wyborem. –

+3

C# 4.0 będzie wprowadzać bardzo innowacyjną funkcję ... Tuple :) –

+0

Muszę to kochać! : P –

20

Mają swoje miejsce. Metoda Int32.TryParse jest dobrym przykładem efektywnego wykorzystania parametru out.

bool result = Int32.TryParse(value, out number); 
if (result) 
{ 
    Console.WriteLine("Converted '{0}' to {1}.", value, number);   
} 
+1

Dobry przykład. TryParse jest jedną z niewielu metod, jakie kiedykolwiek widziałem, która używa out * i * jest usprawiedliwiona. – Jagd

+0

To interesujący przypadek specjalny, ponieważ istnieje TryParse(), aby uniknąć możliwości wystąpienia wyjątku, gdy wartość nie zawiera int. – JeffH

+10

Chciałbym osobiście preferować "int? Int32.TryParse (wartość ciągu)" jako podpis, ponieważ wtedy można użyć? operator, aby określić wartości zastępcze. Ale ta funkcja została napisana przed wprowadzeniem Nullables. – Jimmy

1

ja też zobaczyć bardzo mało wykorzystania parametrów out/ref, choć w SQL czasami łatwiej jest przekazać wartość z powrotem przez parametr niż przez wynikowego (które następnie wymagają użycia DataReader, etc .)

Jednak, na szczęście, właśnie stworzyłem jedną taką rzadką funkcję w języku C#. Sprawdził strukturę danych przypominającą tabelę i zwrócił liczbę wierszy i kolumn w niej (co było trudne do obliczenia, ponieważ tabela mogła mieć rowspany/colspans, podobnie jak w HTML). W tym przypadku obliczenia obu wartości wykonano w tym samym czasie. Rozdzielenie go na dwie funkcje spowodowałoby podwojenie wymagań dotyczących kodu, pamięci i czasu procesora. Tworzenie niestandardowego typu tylko dla tej jednej funkcji do zwrotu również wydaje mi się przesadą.

Są więc chwile, kiedy są najlepsze, ale w większości przypadków można bez nich zrobić dobrze.

1

Klauzula o klauzuli OUTPUT w SQL Server 2005 i później to wielki krok naprzód w uzyskiwaniu wartości pól dla wierszy, których dotyczą instrukcje DML. Pomyśl, że istnieje wiele sytuacji, w których eliminuje to parametry wyjściowe.

W parametrze VB6 parametry ByRef umożliwiają przechodzenie obiektów ADO.

oprócz tych dwóch konkretnych przypadków, które przychodzą na myśl, staram się ich unikać.

1

Tylko w języku SQL ...

Parametry wyjściowe procedury zapisanej są użyteczne.

  1. Załóżmy, że potrzebujesz jednej wartości z powrotem. Czy "utworzysz #table, wstaw ... exec, wybierz @var =". Lub użyć parametru wyjściowego?

  2. W przypadku wywołań klientów parametr wyjściowy jest znacznie szybszy niż przetwarzanie zestawu rekordów.

  3. Używanie wartości RETURN jest ograniczone do liczby całkowitej ze znakiem.

  4. Łatwiejsze do ponownego wykorzystania (np procedura Security Check pomocnik)

  5. Przy użyciu zarówno: zestawy rekordów = dane, parametry wyjściowe = Stan/messages/rowCount etc

  6. Procedury składowane wyjście recordset możliwe, nie należy silnie wpisane jak UDF lub klient kodu

  7. nie zawsze można użyć UDF (np rejestrowania podczas kontroli bezpieczeństwa powyżej)

Jednak dopóki nie używasz generalnie tego samego parametru dla danych wejściowych i wyjściowych, do czasu, aż SQL całkowicie się zmieni, twoje opcje są ograniczone. Mówiąc to, mam jeden przypadek, w którym używam paramteru dla wartości wejściowych i wyjściowych, ale mam dobry powód.

1

Moje dwa centy:
Zgadzam się, że parametry wyjściowe są obowiązującą praktyką. VBA jest często utrzymywany przez ludzi bardzo nowych w programowaniu, a jeśli ktoś, kto zachowuje twój kod, nie zauważy, że parametr jest ByRef, może wprowadzić poważne błędy logiczne. Również ma tendencję do łamania paradygmatu Właściwość/Funkcja/Sub.
Innym powodem, dla którego używanie parametrów jest złe, jest to, że jeśli naprawdę chcesz , aby musiał zwracać więcej niż jedną wartość, istnieje prawdopodobieństwo, że powinieneś mieć te wartości w strukturze danych, takiej jak klasa lub typ zdefiniowany przez użytkownika.
Mogą one jednak rozwiązać niektóre problemy.VB5 (a zatem VBA dla Office 97) nie pozwalał na funkcję zwracania tablicy. Oznaczało to, że wszystko, co powróci lub zmieni tablicę, będzie musiało zostać wykonane za pomocą parametru "out". W VB6 ta zdolność została dodana, ale VB6 wciąż wymusza na parametrach tablicy odwołanie (aby zapobiec nadmiernemu kopiowaniu w pamięci). Teraz możesz może zwrócić wartość z funkcji, która zmienia tablicę. Ale będzie to tylko powolne włosy (z powodu akrobatyki toczącej się za kulisami); może także mylić początkujących z myśleniem, że wejście tablicy nie zostanie zmienione (co będzie prawdą tylko wtedy, gdy ktoś tak to ustrukturyzował). Tak więc stwierdzam, że jeśli mam funkcję, która zmienia tablicę, zmniejsza zamieszanie, aby użyć suba zamiast funkcji (i będzie trochę szybszy).
Innym możliwym scenariuszem jest, jeśli zachowujesz kod i chcesz dodać wartość bez łamania interfejsu, możesz dodać opcjonalny parametr wyjściowy i mieć pewność, że nie zepsujesz żadnego starego kodu. To nie jest dobra praktyka, ale jeśli ktoś chce coś naprawić teraz i nie masz czasu, aby zrobić to "właściwą drogę" i restrukturyzacji wszystko, może to być przydatne dodatek do skrzynki narzędziowej.
Jednakże, jeśli pracujesz od podstaw i musisz zwrócić wiele wartości, powinieneś rozważyć:
1. Zerwanie funkcji.
2. Zwracanie UDT.
3. Zwracanie klasy.