2009-10-08 14 views
28

Me enfrento a algo raro en VBScript. Cuando escribo un procedimiento en el que quiero que el parámetro pase por referencia, la forma de invocar este procedimiento cambia la forma en que se pasa el parámetro.ByRef y ByVal en VBScript

Aquí se muestra un ejemplo:

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 

Y aquí está la salida:

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

U:\> 

Al especificar los parámetros se pasan ByVal, funciona como se esperaba, no importa la forma en que el procedimiento es llamado. Pero cuando se especifican los parámetros se pasan ByRef, que funcionará como se espera si llamar al procedimiento de esta manera:

IncrementByRef Num 

pero no de esta manera:

IncrementByRef(Num) 

Esto parece extraño para mí. ¿Hay alguna manera de asegurarse de que ByRef pase los parámetros, no importa cómo se llame al procedimiento?

Respuesta

38

Eric Lippert tiene un gran artículo sobre el uso de paréntesis en VBScript: What do you mean "cannot use parentheses?" Su ejemplo ilustra uno de los puntos que menciona, a saber: que encierra un argumento ByRef paréntesis pasa como ByVal.

En resumen, los paréntesis en las llamadas de subrutina de VBScript se pueden poner no solo alrededor de la lista de argumentos, sino también en torno a argumentos individuales (en cuyo caso son forzados ByVal). Y VBScript solo espera que la lista de argumentos esté entre paréntesis si se usa la palabra clave Call. Dado que la llamada IncrementByRef(Num) no utiliza la palabra clave Call, VBScript trata los paréntesis como se aplica al argumento de subrutina y así lo pasa ByVal en lugar de ByRef.

Confuso, pero así es como funciona.

+0

... Así de simple? ¡Y estuve luchando por ello durante una hora! Gracias, +1. – Jet

18

Es una característica, no un error:
http://msdn.microsoft.com/en-us/library/ee478101.aspx

Un parámetro ByRef se pasa por valor si el argumento está encerrado entre paréntesis y los paréntesis no se aplican a la lista de argumentos.

Los paréntesis se aplican a la lista de argumentos, si una de las siguientes situaciones:

  • La declaración es una llamada a la función que tiene una asignación para el valor devuelto.

  • La declaración utiliza la palabra clave de llamada. (La palabra clave Call opcionalmente se puede utilizar para una llamada de subrutina, o para una llamada de función sin una asignación.)

Así que trate de usar la palabra clave llamada o de que éste devuelve un valor.

+6

Ese es uno de los temas más confusos MSDN relacionados con VBScript que he visto –

7

Para ser claros. Los paréntesis tienen tres propósitos diferentes.

  1. utilizan para incluir una lista de argumentos al definir o llamando al procedimiento
  2. Para indicar un indexador de una matriz.
  3. Como operador en una expresión.

Hay dos formas de llamar a un procedimiento como una declaración o como una expresión.

Expresión: -

x = func(y) 

Declaración: -

func y 

Nota la palabra clave Call invoca el procedimiento como si fuera parte de una expresión por lo tanto, la lista de argumentos debe estar contenido en los paréntesis.

En el anterior que y en sí mismo representa una expession muy simple. Bien podríamos haber usado y + z en este momento. De hecho, podemos usar cualquier expresión válida en este punto, incluida una que use el operador paréntesis. Por ejemplo: -

x = (y) 

es una expresión válida. De ahí que cuando se hace: -

func(y) 

VBScript ve la llamada a func a la que se pasa el resultado de la expresión (y). Ahora, incluso si func define este parámetro como ByRef, el valor en y no se vería afectado porque y no se pasó realmente como parámetro. Lo que se pasó fue el resultado de la expresión (y) que se almacenará en algún lugar temporal. Incluso si esta tienda temporal se modifica por func, se descartaría posteriormente y, por lo tanto, tiene el mismo comportamiento si el parámetro se hubiera marcado ByVal.

2
IncrementByRef Num 

llamadas y incrementos usando una referencia a Num

IncrementByRef (47 + 3) 

llamadas y incrementos usando una referencia a "50". Que se descarta al salir

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

Son todos legales en BASIC, como lo fueron en FORTRAN. Como es notorio, en una FORTRAN temprana, pasando por ref permitió que cambie el valor de expresiones como

5 

que era suficientemente confuso que los primeros compiladores solamente muy pequeñas, FORTRAN tenían ese tipo de comportamiento.

-1

Es simple.Cuando se crea una función o sub y se les puede llamar con este manera:

Por ningún valor de retorno:

myFunction "This is a reference" 

Por valor de retorno:

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

No estoy seguro de entender la pregunta o respuestas, pero voy a compartir esto.

Independientemente de si tiene una sub-rutina de función, definir los parámetros pasados ​​en ByVal o ByRef determinará si el valor del parámetro conserva su valor fuera de la sub-rutina o llamada de función. Si tengo la siguiente función:

Function ThisFByRef(ByRef MyValue) 
End Function 

Todo lo que he hecho para el parámetro dentro de la función (o sub-rutina) conservará su valor después de que la función se ha completado. ByVal y ByRef están asociados con el alcance de la sub-rutina o función. Cualquier parámetro que se pase ByVal no retendrá los cambios que ocurran dentro de la subrutina o función llamada. Alternativamente, cualquier parámetro que pase ByRef retendrá el valor en el que fue cambiado dentro de la sub-rutina o función. La devolución de un valor solo puede realizarse con una Función y no con una Sub-Rutina y no afecta el valor del parámetro pasado a menos que el parámetro pase ByRef y se cambie dentro de la Función. Por ejemplo:

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

En mi humilde opinión, su respuesta no aclara mi punto, que me pareció extraño que después de llamar a 'ThisFValue = ThisByRef (x)', x contiene 1, pero si lo llamo así 'ThisByRef (x)', x contiene 0. Same función, mismo parámetro, pero diferente resultado! –