2009-10-08 7 views
28

Mam do czynienia z czymś dziwnym w VBScript. Podczas pisania procedury, w której chcę, aby parametr był przekazywany przez odniesienie, sposób wywoływania tej procedury zmienia sposób przekazywania parametru!ByRef i ByVal w VBScript

Oto przykład:

Sub IncrementByRef(ByRef Value) 
    Value = Value + 1 
End Sub 

Sub IncrementByVal(ByVal Value) 
    Value = Value + 1 
End Sub 

Dim Num 
Num = 10 
WScript.Echo "Num : " & Num 
IncrementByRef(Num) : WScript.Echo "IncrementByRef(Num) : " & Num 
IncrementByRef Num : WScript.Echo "IncrementByRef Num : " & Num 
IncrementByVal(Num) : WScript.Echo "IncrementByVal(Num) : " & Num 
IncrementByVal Num : WScript.Echo "IncrementByVal Num : " & Num 

I tu jest wyjście:

U:\>cscript //nologo byrefbyval.vbs 
Num : 10 
IncrementByRef(Num) : 10 
IncrementByRef Num : 11 
IncrementByVal(Num) : 11 
IncrementByVal Num : 11 

U:\> 

Po określeniu parametrów przekazywanych ByVal, to działa zgodnie z oczekiwaniami, bez względu na sposób procedura jest nazywa. Ale kiedy określający parametry są przekazywane ByRef, to będzie działać zgodnie z oczekiwaniami, jeśli wywołanie procedura w ten sposób:

IncrementByRef Num 

ale nie w ten sposób:

IncrementByRef(Num) 

To wydaje mi się dziwne. Czy istnieje sposób, aby upewnić się, że parametry są przekazywane ByRef, bez względu na sposób wywołania procedury?

Odpowiedz

38

Eric Lippert ma wielki artykuł o użyciu nawiasów w VBScript: What do you mean "cannot use parentheses?" Twój przykład ilustruje jeden z punktów Wspomina, a mianowicie: osłania ByRef argumentu w nawiasach przekazuje je jako ByVal.

Podsumowując, nawiasy w wywołaniach podprogramów VBScript można umieszczać nie tylko wokół listy argumentów, ale także wokół poszczególnych argumentów (w tym przypadku są one wymuszane ByVal). A VBScript oczekuje, że lista argumentów zostanie ujęta w nawiasach, jeśli użyte zostanie słowo kluczowe Call. Ponieważ wywołanie IncrementByRef(Num) nie używa słowa kluczowego Call, VBScript traktuje nawiasy jako stosowane do argumentu podprogramu, a zatem przekazuje je ByVal zamiast ByRef.

Mylące, ale tak to działa.

+0

... Tak prosty? I walczyłem o to przez godzinę! Dzięki, +1. – Jet

18

Jest to cecha, a nie bug:
http://msdn.microsoft.com/en-us/library/ee478101.aspx

parametr a ByRef jest przekazywane przez wartość, jeśli argument jest w nawiasach i nawiasy nie mają zastosowania do listy argumentów.

Nawiasy zastosowania do listy argumentów, jeśli jeden z następujących warunków:

  • Stwierdzenie to wywołanie funkcji, która ma zadanie do zwracanej wartości.

  • Instrukcja używa słowa kluczowego Call. (Słowo kluczowe połączeń może być ewentualnie wykorzystane do wywołania podprogramu albo do wywołania funkcji bez przydziału.)

Więc spróbuj użyć słowa kluczowego zadzwonić lub konieczności zwróci wartość.

+6

Jest to jeden z najbardziej mylących tematów MSDN związanych z VBScript, jakie widziałem w życiu –

7

Aby było jasne. Nawiasy mają trzy różne cele.

  1. Używane dołączyć listę argumentów przy definiowaniu lub procedurę
  2. nazywając Aby wskazać podziałowe na tablicy.
  3. Jako operator w wyrażeniu.

Istnieją dwa sposoby wywołania procedury w formie instrukcji lub wyrażenia.

Expression: -

x = func(y) 

komunikat: -

func y 

Uwaga słowo kluczowe Call wywołuje procedurę tak, jakby były częścią wyrażenia stąd lista argument musi być zawarte w nawiasach.

W powyższym przykładzie sama y reprezentuje bardzo prostą ekspedycję. Moglibyśmy w tym momencie użyć y + z. W rzeczywistości możemy użyć dowolnego prawidłowego wyrażenia w tym miejscu, w tym takiego, które używa operatora nawiasów. Na przykład: -

x = (y) 

jest prawidłowym wyrażeniem. Stąd kiedy zrobić: -

func(y) 

VBScript widzi wezwanie do func do którego przekazywany jest wynikiem ekspresji (y). Teraz nawet jeśli func zdefiniuje ten parametr jako ByRef, wartość w y będzie niezmieniona, ponieważ y nie został faktycznie przekazany jako parametr. To, co zostało przekazane, było wynikiem wyrażenia (y), które byłoby przechowywane gdzieś tymczasowo. Nawet jeśli ten tymczasowy sklep zostanie zmodyfikowany przez func, zostanie on później odrzucony, a zatem zachowuje się tak samo, gdyby parametr został oznaczony jako ByVal.

2
IncrementByRef Num 

połączenia i przyrosty wykorzystujące odniesienie do Num

IncrementByRef (47 + 3) 

połączeń i przyrosty pomocą odniesienie do "50". Który jest odrzucany przy wyjściu.

IncrementByRef (Num) 
IncrementByRef (Num + 18)*5 
IncrementByRef Cint("32") 

Wszystkie są legalne w języku BASIC, tak jak w FORTRAN. Notorycznie, w jednym z wczesnych FORTRAN, przechodząc przez ref pozwalał na zmianę wartości wyrażeń jak

5 

co było wystarczająco skomplikowane, że tylko bardzo małe, wczesne Fortran miał tego rodzaju zachowania.

-1

To jest proste.Po utworzeniu funkcji lub sub i można do nich dzwonić z tymi sposób:

Dla nie zwraca wartości:

myFunction "This is a reference" 

Dla Zwracana wartość:

myValue = myFunction ("This is a reference") 
0

Nie jestem pewien, śledzę pytanie lub odpowiedzi, ale podzielę się tym.

Bez względu na to, czy masz podprogram funkcji, zdefiniowanie parametrów przekazanych w ByVal lub ByRef określi, czy wartość parametru zachowuje swoją wartość poza podprocedurą lub wywołaniem funkcji. Jeśli mam następującą funkcję:

Function ThisFByRef(ByRef MyValue) 
End Function 

Wszystko, co zrobić, aby parametr w funkcji (lub sub-rutyny) zachowa swoją wartość po zakończeniu funkcji. ByVal i ByRef są powiązane z zakresem podprocedury lub funkcji. Każdy parametr przekazany ByVal nie zachowuje zmian, które występują w wywołanej podprocedurze lub funkcji. Alternatywnie, dowolny parametr, który zostanie przekazany, będzie zachowywał wartość, do której został zmieniony w ramach podprocedury lub funkcji. Zwracanie wartości można wykonać tylko za pomocą funkcji, a nie pod-procedury i nie wpływa ona na wartość parametru przekazywanego, chyba że parametr zostanie przekazany ByRef i zmieniony w ramach funkcji. Na przykład:

Dim x 
Dim ThisFValue 

x = 0 
ThisFValue = ThisFByRef(x) 
At this point the values would be: 
ThisFValue = 2 
x = 1 

x = 0 
ThisFValue = ThisFByVal(x) 
At this point the values would be: 
ThisFValue = 2 
x = 0 

Function ThisFByRef(ByRef x) 
    x = x + 1 
    ThisFByRef = x + 1 
End Function 

Function ThisFByVal(ByVal x) 
    x = x + 1 
    ThisFByVal = x + 1 
End Function 
+1

IMHO, twoja odpowiedź nie wyjaśnia mojej kwestii, co było dziwne, że po wywołaniu 'ThisFValue = ThisByRef (x)', x zawiera 1, ale jeśli nazywam to tak: 'ThisByRef (x)', x zawiera 0. Same funkcja, ten sam parametr, ale inny wynik! –