From 4227c86a5e7020958e0ba4aba2431b14c14dc417 Mon Sep 17 00:00:00 2001 From: skycommand <17097175+skycommand@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:23:48 +0330 Subject: [PATCH 1/3] about_Ref.md: Relationship between [ref] and [PSReference] Added a new section, "Relationship between [ref] and System.Management.Automation.PSReference" to about_Ref.md. --- .../About/about_Ref.md | 66 +++++++++++++++--- .../About/about_Ref.md | 69 ++++++++++++++++--- .../About/about_Ref.md | 60 ++++++++++++++-- 3 files changed, 174 insertions(+), 21 deletions(-) diff --git a/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md b/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md index 8116e6d81857..4f1f76b538a7 100644 --- a/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md +++ b/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md @@ -6,7 +6,6 @@ online version: https://learn.microsoft.com/powershell/module/microsoft.powershe schema: 2.0.0 title: about_Ref --- - # about_Ref ## Short description @@ -17,9 +16,9 @@ of a variable that is passed to it. ## Long description -You can pass variables to functions *by reference* or *by value*. +You can pass variables to functions _by reference_ or _by value_. -When you pass a variable *by value*, you are passing a copy of the data. +When you pass a variable _by value_, you are passing a copy of the data. In the following example, the function changes the value of the variable passed to it. In PowerShell, integers are value types so they are passed by value. @@ -42,9 +41,9 @@ $var In the following example, a variable containing a `Hashtable` is passed to a function. `Hashtable` is an object type so by default it is passed to the -function *by reference*. +function _by reference_. -When passing a variable *by reference*, the function can change the data and +When passing a variable _by reference_, the function can change the data and that change persists after the function executes. ```powershell @@ -71,10 +70,10 @@ scope. You can code your functions to take a parameter as a reference, regardless of the type of data passed. This requires that you specify the parameters type -as `System.Management.Automation.PSReference`, or `[ref]`. +as `[ref]`. -When using references, you must use the `Value` property of the -`System.Management.Automation.PSReference` type to access your data. +When using references, you must use the `Value` property of the `[ref]` type to +access your data. ```powershell Function Test([ref]$data) @@ -86,7 +85,7 @@ Function Test([ref]$data) To pass a variable to a parameter that expects a reference, you must type cast your variable as a reference. -> [!NOTE] +> [!IMPORTANT] > The brackets and parenthesis are BOTH required. ```powershell @@ -149,6 +148,52 @@ $i = 0;$iRef = 1 Only the reference type's variable was changed. +### Relationship between [ref] and System.Management.Automation.PSReference + +`Ref` is both a type accelerator for `System.Management.Automation.PSReference` +(see [about_Type_Accelerators] for details) and a reserved keyword that +PowerShell treats especially. Hence, `ref` and `PSReference` are not +equivalents. The following script demonstrates their difference: + +```powershell +$x = 1 + +$a = [ref] $x +$b = [System.Management.Automation.PSReference] $x +$c = [ref] $x + +$x +=4 +$a.Value +=3 +$b.Value +=2 +$c.Value +=1 + +$x, $a.Value, $b.Value, $c.Value | ForEach-Object { + Write-Output $PSItem +} +``` + +The output of this script is: + +```powershell +9 +9 +3 +9 +``` + +The above script: + +- Creates an integer `$x` variable and assigns `1` to it. +- Creates pointers `$a` and `$c` of `[ref]` types and points them at `$x`. +- Creates pointer `$b` of `[PSReference]` type and points it, not at `$x`, but + a copy thereof, because PowerShell treats `[ref]` and `[PSReference]` + differently. +- Adds 4 to `$x`, 3 to `$a`'s value, 2 to `$b`'s value, and 1 to `$a`'s value. + +In the script above, `$x`, `$a.Value`, and `$c.Value` point to the same memory +location. They are the same, i.e., 1 + 4 + 3 + 1 = 9. But `$b.Value` refers to +a copy of `$x` at the time of its creation. Hence, it contains 1 + 2 = 3. + ## See also - [about_Variables](about_Variables.md) @@ -156,3 +201,6 @@ Only the reference type's variable was changed. - [about_Functions](about_Functions.md) - [about_Script_Blocks](about_Script_Blocks.md) - [about_Scopes](about_scopes.md) +- [about_Type_accelerators] + +[about_Type_accelerators]: about_Type_Accelerators.md diff --git a/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md b/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md index acbfbb151fc4..d62120ca9f96 100644 --- a/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md +++ b/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md @@ -9,15 +9,16 @@ title: about_Ref # about_Ref ## Short description + Describes how to create and use a reference type variable. You can use reference type variables to permit a function to change the value of a variable that is passed to it. ## Long description -You can pass variables to functions *by reference* or *by value*. +You can pass variables to functions _by reference_ or _by value_. -When you pass a variable *by value*, you are passing a copy of the data. +When you pass a variable _by value_, you are passing a copy of the data. In the following example, the function changes the value of the variable passed to it. In PowerShell, integers are value types so they are passed by value. @@ -40,9 +41,9 @@ $var In the following example, a variable containing a `Hashtable` is passed to a function. `Hashtable` is an object type so by default it is passed to the -function *by reference*. +function _by reference_. -When passing a variable *by reference*, the function can change the data and +When passing a variable _by reference_, the function can change the data and that change persists after the function executes. ```powershell @@ -69,10 +70,10 @@ scope. You can code your functions to take a parameter as a reference, regardless of the type of data passed. This requires that you specify the parameters type -as `System.Management.Automation.PSReference`, or `[ref]`. +as `[ref]`. -When using references, you must use the `Value` property of the -`System.Management.Automation.PSReference` type to access your data. +When using references, you must use the `Value` property of the `[ref]` type to +access your data. ```powershell Function Test([ref]$data) @@ -84,7 +85,7 @@ Function Test([ref]$data) To pass a variable to a parameter that expects a reference, you must type cast your variable as a reference. -> [!NOTE] +> [!IMPORTANT] > The brackets and parenthesis are BOTH required. ```powershell @@ -147,6 +148,52 @@ $i = 0;$iRef = 1 Only the reference type's variable was changed. +### Relationship between [ref] and System.Management.Automation.PSReference + +`Ref` is both a type accelerator for `System.Management.Automation.PSReference` +(see [about_Type_Accelerators] for details) and a reserved keyword that +PowerShell [treats][2] [especially][1]. Hence, `ref` and `PSReference` are not +equivalents. The following script demonstrates their difference: + +```powershell +$x = 1 + +$a = [ref] $x +$b = [System.Management.Automation.PSReference] $x +$c = [ref] $x + +$x +=4 +$a.Value +=3 +$b.Value +=2 +$c.Value +=1 + +$x, $a.Value, $b.Value, $c.Value | ForEach-Object { + Write-Output $PSItem +} +``` + +The output of this script is: + +```powershell +9 +9 +3 +9 +``` + +The above script: + +- Creates an integer `$x` variable and assigns `1` to it. +- Creates pointers `$a` and `$c` of `[ref]` types and points them at `$x`. +- Creates pointer `$b` of `[PSReference]` type and points it, not at `$x`, but + a copy thereof, because PowerShell treats `[ref]` and `[PSReference]` + differently. +- Adds 4 to `$x`, 3 to `$a`'s value, 2 to `$b`'s value, and 1 to `$a`'s value. + +In the script above, `$x`, `$a.Value`, and `$c.Value` point to the same memory +location. They are the same, i.e., 1 + 4 + 3 + 1 = 9. But `$b.Value` refers to +a copy of `$x` at the time of its creation. Hence, it contains 1 + 2 = 3. + ## See also - [about_Variables](about_Variables.md) @@ -154,3 +201,9 @@ Only the reference type's variable was changed. - [about_Functions](about_Functions.md) - [about_Script_Blocks](about_Script_Blocks.md) - [about_Scopes](about_scopes.md) +- [about_Type_accelerators] + +[about_Type_accelerators]: about_Type_Accelerators.md + +[1]: https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/parser/ast.cs#L7983 +[2]: https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/parser/Compiler.cs#L6121 \ No newline at end of file diff --git a/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md b/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md index 8fcfc9f73b2c..2f3f3948e5be 100644 --- a/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md +++ b/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md @@ -70,10 +70,10 @@ scope. You can code your functions to take a parameter as a reference, regardless of the type of data passed. This requires that you specify the parameters type -as `System.Management.Automation.PSReference`, or `[ref]`. +as `[ref]`. -When using references, you must use the `Value` property of the -`System.Management.Automation.PSReference` type to access your data. +When using references, you must use the `Value` property of the `[ref]` type to +access your data. ```powershell Function Test([ref]$data) @@ -85,7 +85,7 @@ Function Test([ref]$data) To pass a variable to a parameter that expects a reference, you must type cast your variable as a reference. -> [!NOTE] +> [!IMPORTANT] > The brackets and parenthesis are BOTH required. ```powershell @@ -148,6 +148,52 @@ $i = 0;$iRef = 1 Only the reference type's variable was changed. +### Relationship between [ref] and System.Management.Automation.PSReference + +`Ref` is both a type accelerator for `System.Management.Automation.PSReference` +(see [about_Type_Accelerators] for details) and a reserved keyword that +PowerShell [treats][2] [especially][1]. Hence, `ref` and `PSReference` are not +equivalents. The following script demonstrates their difference: + +```powershell +$x = 1 + +$a = [ref] $x +$b = [System.Management.Automation.PSReference] $x +$c = [ref] $x + +$x +=4 +$a.Value +=3 +$b.Value +=2 +$c.Value +=1 + +$x, $a.Value, $b.Value, $c.Value | ForEach-Object { + Write-Output $PSItem +} +``` + +The output of this script is: + +```powershell +9 +9 +3 +9 +``` + +The above script: + +- Creates an integer `$x` variable and assigns `1` to it. +- Creates pointers `$a` and `$c` of `[ref]` types and points them at `$x`. +- Creates pointer `$b` of `[PSReference]` type and points it, not at `$x`, but + a copy thereof, because PowerShell treats `[ref]` and `[PSReference]` + differently. +- Adds 4 to `$x`, 3 to `$a`'s value, 2 to `$b`'s value, and 1 to `$a`'s value. + +In the script above, `$x`, `$a.Value`, and `$c.Value` point to the same memory +location. They are the same, i.e., 1 + 4 + 3 + 1 = 9. But `$b.Value` refers to +a copy of `$x` at the time of its creation. Hence, it contains 1 + 2 = 3. + ## See also - [about_Variables](about_Variables.md) @@ -155,3 +201,9 @@ Only the reference type's variable was changed. - [about_Functions](about_Functions.md) - [about_Script_Blocks](about_Script_Blocks.md) - [about_Scopes](about_scopes.md) +- [about_Type_accelerators] + +[about_Type_accelerators]: about_Type_Accelerators.md + +[1]: https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/parser/ast.cs#L7983 +[2]: https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/parser/Compiler.cs#L6121 \ No newline at end of file From 6cfa7df44517b5c3b80e7824bb9c72d6cc627357 Mon Sep 17 00:00:00 2001 From: Sean Wheeler Date: Thu, 12 Dec 2024 14:27:55 -0600 Subject: [PATCH 2/3] Updated examples and added more context --- .../About/about_Ref.md | 146 +++++++++++------ .../About/about_Ref.md | 149 +++++++++++------- .../About/about_Ref.md | 149 +++++++++++------- 3 files changed, 285 insertions(+), 159 deletions(-) diff --git a/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md b/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md index 4f1f76b538a7..2969894dd61f 100644 --- a/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md +++ b/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md @@ -1,7 +1,7 @@ --- description: Describes how to create and use a reference type variable. You can use reference type variables to permit a function to change the value of a variable that is passed to it. Locale: en-US -ms.date: 08/24/2018 +ms.date: 12/12/2024 online version: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_ref?view=powershell-5.1&WT.mc_id=ps-gethelp schema: 2.0.0 title: about_Ref @@ -10,18 +10,25 @@ title: about_Ref ## Short description -Describes how to create and use a reference type variable. You can use -reference type variables to permit a function to change the value -of a variable that is passed to it. +Describes how to create and use a reference type variable. ## Long description -You can pass variables to functions _by reference_ or _by value_. +You can pass variables to functions _by reference_ or _by value_. When you pass +a variable _by value_, you are passing a copy of the data. When you pass a +variable _by reference_, you are passing a reference to the original value. +This allows the function to change the value of the variable that is passed to +it.Reference types are created using `[ref]`, which is the type accelerator for +the `[System.Management.Automation.PSReference]` type. -When you pass a variable _by value_, you are passing a copy of the data. +The primary purpose of `[ref]` is to enable passing PowerShell variables by +reference to .NET method parameters marked as `ref`, `out`, or `in`. You can +also define your own PowerShell function that take `[ref]` type parameters. In +this usage, `[ref]` is applied to a _variable_, and the resulting `[ref]` +instance can be used to indirectly modify that variable's value. In the following example, the function changes the value of the variable passed -to it. In PowerShell, integers are value types so they are passed by value. +to it. In PowerShell, integers are value types so they're passed by value. Therefore, the value of `$var` is unchanged outside the scope of the function. ```powershell @@ -40,7 +47,7 @@ $var ``` In the following example, a variable containing a `Hashtable` is passed to a -function. `Hashtable` is an object type so by default it is passed to the +function. `Hashtable` is an object type so by default it's passed to the function _by reference_. When passing a variable _by reference_, the function can change the data and @@ -66,7 +73,7 @@ Test New Text The function adds a new key-value pair that persists outside of the function's scope. -### Writing functions to accept reference parameters +## Writing functions to accept reference parameters You can code your functions to take a parameter as a reference, regardless of the type of data passed. This requires that you specify the parameters type @@ -98,7 +105,7 @@ $var 3 ``` -### Passing references to .NET methods +## Passing references to .NET methods Some .NET methods may require you to pass a variable as a reference. When the method's definition uses the keywords `in`, `out`, or `ref` on a @@ -126,7 +133,7 @@ PS> $number 15 ``` -### References and scopes +## References and scopes References allow the value of a variable in the parent scope to be changed within a child scope. @@ -148,59 +155,96 @@ $i = 0;$iRef = 1 Only the reference type's variable was changed. -### Relationship between [ref] and System.Management.Automation.PSReference +## Using `[ref]` as a general-purpose object holder -`Ref` is both a type accelerator for `System.Management.Automation.PSReference` -(see [about_Type_Accelerators] for details) and a reserved keyword that -PowerShell treats especially. Hence, `ref` and `PSReference` are not -equivalents. The following script demonstrates their difference: +You can also use `[ref]` as a general-purpose object holder. In this usage, +`[ref]` is applied to a _value_ instead of a variable. Typically, the value is +an instance of a _value type_, like a number. In most scenarios you can use a +regular variable or parameter instead. However, this technique is useful in +scenarios where passing an explicit value holder is undesired (for brevity) or +not possible, such as in script-block parameter values. + +For example, you can use script-block parameter values to calculate the value +of **NewName** parameter of the `Rename-Item` cmdlet. The `Rename-Item` cmdlet +allows you to pipe items to it. The command run the script block passed to the +**NewName** for each item in the pipeline. The script block run in a child +scope. Modifying a variable in the caller's scope directly won't help and you +can't pass arguments to the script block in this context. + +In this example, the script block passed to the **NewName** parameter +increments the value of `$iRef` for each item in the pipeline. The script block +creates a new name by adding a number to the beginning of the filename. ```powershell -$x = 1 +$iRef = [ref] 0 +Get-ChildItem -File $setPath | + Rename-Item -NewName { '{0} - {1}' -f $iRef.Value++,$_.Name } +``` -$a = [ref] $x -$b = [System.Management.Automation.PSReference] $x -$c = [ref] $x +## Difference between `[ref]` and `[System.Management.Automation.PSReference]` -$x +=4 -$a.Value +=3 -$b.Value +=2 -$c.Value +=1 +A reference type variable is created using -$x, $a.Value, $b.Value, $c.Value | ForEach-Object { - Write-Output $PSItem -} -``` +Even though `[ref]` is a type accelerator for +`[System.Management.Automation.PSReference]`, they behave differently. + +- When you use `[ref]` to cast a variable, PowerShell creates reference object + that contains reference to the original instance of the variable. +- When you use `[System.Management.Automation.PSReference]` to cast a variable, + PowerShell creates reference object that contains a copy of the variable, + rather than a reference to the original instance. -The output of this script is: +For example, the following script creates a variable `$x` and two reference +objects. ```powershell -9 -9 -3 -9 +PS> $int = 1 +PS> $aRef = [ref] $int +PS> $bRef = [System.Management.Automation.PSReference] $int +PS> $int +1 +PS> $aRef, $bRef + +Value +----- + 1 + 1 ``` -The above script: +At this point, both reference object have the same value as `$int`. By adding +different values to the reference objects, we can see that `$aRef`, which was +created using `[ref]`, is a reference to the original instance of `$int`. +`$bRef` was created using `[System.Management.Automation.PSReference]` is a +copy of the variable. -- Creates an integer `$x` variable and assigns `1` to it. -- Creates pointers `$a` and `$c` of `[ref]` types and points them at `$x`. -- Creates pointer `$b` of `[PSReference]` type and points it, not at `$x`, but - a copy thereof, because PowerShell treats `[ref]` and `[PSReference]` - differently. -- Adds 4 to `$x`, 3 to `$a`'s value, 2 to `$b`'s value, and 1 to `$a`'s value. +```powershell +PS> $aRef.Value+=2 +PS> $bRef.Value+=5 +PS> $int +3 +PS> $aRef, $bRef -In the script above, `$x`, `$a.Value`, and `$c.Value` point to the same memory -location. They are the same, i.e., 1 + 4 + 3 + 1 = 9. But `$b.Value` refers to -a copy of `$x` at the time of its creation. Hence, it contains 1 + 2 = 3. +Value +----- + 3 + 6 +``` ## See also -- [about_Variables](about_Variables.md) -- [about_Environment_Variables](about_Environment_Variables.md) -- [about_Functions](about_Functions.md) -- [about_Script_Blocks](about_Script_Blocks.md) -- [about_Scopes](about_scopes.md) -- [about_Type_accelerators] - -[about_Type_accelerators]: about_Type_Accelerators.md +- [about_Variables][06] +- [about_Environment_Variables][01] +- [about_Functions][02] +- [about_Script_Blocks][04] +- [about_Scopes][03] +- [about_Type_Accelerators][05] +- [System.Management.Automation.PSReference][07] + + +[01]: about_Environment_Variables.md +[02]: about_Functions.md +[03]: about_scopes.md +[04]: about_Script_Blocks.md +[05]: about_Type_Accelerators.md +[06]: about_Variables.md +[07]: xref:System.Management.Automation.PSReference diff --git a/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md b/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md index d62120ca9f96..679de9a24584 100644 --- a/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md +++ b/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md @@ -1,7 +1,7 @@ --- description: Describes how to create and use a reference type variable. You can use reference type variables to permit a function to change the value of a variable that is passed to it. Locale: en-US -ms.date: 08/24/2018 +ms.date: 12/12/2024 online version: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_ref?view=powershell-7.4&WT.mc_id=ps-gethelp schema: 2.0.0 title: about_Ref @@ -10,18 +10,25 @@ title: about_Ref ## Short description -Describes how to create and use a reference type variable. You can use -reference type variables to permit a function to change the value -of a variable that is passed to it. +Describes how to create and use a reference type variable. ## Long description -You can pass variables to functions _by reference_ or _by value_. +You can pass variables to functions _by reference_ or _by value_. When you pass +a variable _by value_, you are passing a copy of the data. When you pass a +variable _by reference_, you are passing a reference to the original value. +This allows the function to change the value of the variable that is passed to +it.Reference types are created using `[ref]`, which is the type accelerator for +the `[System.Management.Automation.PSReference]` type. -When you pass a variable _by value_, you are passing a copy of the data. +The primary purpose of `[ref]` is to enable passing PowerShell variables by +reference to .NET method parameters marked as `ref`, `out`, or `in`. You can +also define your own PowerShell function that take `[ref]` type parameters. In +this usage, `[ref]` is applied to a _variable_, and the resulting `[ref]` +instance can be used to indirectly modify that variable's value. In the following example, the function changes the value of the variable passed -to it. In PowerShell, integers are value types so they are passed by value. +to it. In PowerShell, integers are value types so they're passed by value. Therefore, the value of `$var` is unchanged outside the scope of the function. ```powershell @@ -40,7 +47,7 @@ $var ``` In the following example, a variable containing a `Hashtable` is passed to a -function. `Hashtable` is an object type so by default it is passed to the +function. `Hashtable` is an object type so by default it's passed to the function _by reference_. When passing a variable _by reference_, the function can change the data and @@ -66,7 +73,7 @@ Test New Text The function adds a new key-value pair that persists outside of the function's scope. -### Writing functions to accept reference parameters +## Writing functions to accept reference parameters You can code your functions to take a parameter as a reference, regardless of the type of data passed. This requires that you specify the parameters type @@ -98,7 +105,7 @@ $var 3 ``` -### Passing references to .NET methods +## Passing references to .NET methods Some .NET methods may require you to pass a variable as a reference. When the method's definition uses the keywords `in`, `out`, or `ref` on a @@ -126,7 +133,7 @@ PS> $number 15 ``` -### References and scopes +## References and scopes References allow the value of a variable in the parent scope to be changed within a child scope. @@ -148,62 +155,96 @@ $i = 0;$iRef = 1 Only the reference type's variable was changed. -### Relationship between [ref] and System.Management.Automation.PSReference +## Using `[ref]` as a general-purpose object holder -`Ref` is both a type accelerator for `System.Management.Automation.PSReference` -(see [about_Type_Accelerators] for details) and a reserved keyword that -PowerShell [treats][2] [especially][1]. Hence, `ref` and `PSReference` are not -equivalents. The following script demonstrates their difference: +You can also use `[ref]` as a general-purpose object holder. In this usage, +`[ref]` is applied to a _value_ instead of a variable. Typically, the value is +an instance of a _value type_, like a number. In most scenarios you can use a +regular variable or parameter instead. However, this technique is useful in +scenarios where passing an explicit value holder is undesired (for brevity) or +not possible, such as in script-block parameter values. + +For example, you can use script-block parameter values to calculate the value +of **NewName** parameter of the `Rename-Item` cmdlet. The `Rename-Item` cmdlet +allows you to pipe items to it. The command run the script block passed to the +**NewName** for each item in the pipeline. The script block run in a child +scope. Modifying a variable in the caller's scope directly won't help and you +can't pass arguments to the script block in this context. + +In this example, the script block passed to the **NewName** parameter +increments the value of `$iRef` for each item in the pipeline. The script block +creates a new name by adding a number to the beginning of the filename. ```powershell -$x = 1 +$iRef = [ref] 0 +Get-ChildItem -File $setPath | + Rename-Item -NewName { '{0} - {1}' -f $iRef.Value++,$_.Name } +``` -$a = [ref] $x -$b = [System.Management.Automation.PSReference] $x -$c = [ref] $x +## Difference between `[ref]` and `[System.Management.Automation.PSReference]` -$x +=4 -$a.Value +=3 -$b.Value +=2 -$c.Value +=1 +A reference type variable is created using -$x, $a.Value, $b.Value, $c.Value | ForEach-Object { - Write-Output $PSItem -} -``` +Even though `[ref]` is a type accelerator for +`[System.Management.Automation.PSReference]`, they behave differently. + +- When you use `[ref]` to cast a variable, PowerShell creates reference object + that contains reference to the original instance of the variable. +- When you use `[System.Management.Automation.PSReference]` to cast a variable, + PowerShell creates reference object that contains a copy of the variable, + rather than a reference to the original instance. -The output of this script is: +For example, the following script creates a variable `$x` and two reference +objects. ```powershell -9 -9 -3 -9 +PS> $int = 1 +PS> $aRef = [ref] $int +PS> $bRef = [System.Management.Automation.PSReference] $int +PS> $int +1 +PS> $aRef, $bRef + +Value +----- + 1 + 1 ``` -The above script: +At this point, both reference object have the same value as `$int`. By adding +different values to the reference objects, we can see that `$aRef`, which was +created using `[ref]`, is a reference to the original instance of `$int`. +`$bRef` was created using `[System.Management.Automation.PSReference]` is a +copy of the variable. -- Creates an integer `$x` variable and assigns `1` to it. -- Creates pointers `$a` and `$c` of `[ref]` types and points them at `$x`. -- Creates pointer `$b` of `[PSReference]` type and points it, not at `$x`, but - a copy thereof, because PowerShell treats `[ref]` and `[PSReference]` - differently. -- Adds 4 to `$x`, 3 to `$a`'s value, 2 to `$b`'s value, and 1 to `$a`'s value. +```powershell +PS> $aRef.Value+=2 +PS> $bRef.Value+=5 +PS> $int +3 +PS> $aRef, $bRef -In the script above, `$x`, `$a.Value`, and `$c.Value` point to the same memory -location. They are the same, i.e., 1 + 4 + 3 + 1 = 9. But `$b.Value` refers to -a copy of `$x` at the time of its creation. Hence, it contains 1 + 2 = 3. +Value +----- + 3 + 6 +``` ## See also -- [about_Variables](about_Variables.md) -- [about_Environment_Variables](about_Environment_Variables.md) -- [about_Functions](about_Functions.md) -- [about_Script_Blocks](about_Script_Blocks.md) -- [about_Scopes](about_scopes.md) -- [about_Type_accelerators] - -[about_Type_accelerators]: about_Type_Accelerators.md - -[1]: https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/parser/ast.cs#L7983 -[2]: https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/parser/Compiler.cs#L6121 \ No newline at end of file +- [about_Variables][06] +- [about_Environment_Variables][01] +- [about_Functions][02] +- [about_Script_Blocks][04] +- [about_Scopes][03] +- [about_Type_Accelerators][05] +- [System.Management.Automation.PSReference][07] + + +[01]: about_Environment_Variables.md +[02]: about_Functions.md +[03]: about_scopes.md +[04]: about_Script_Blocks.md +[05]: about_Type_Accelerators.md +[06]: about_Variables.md +[07]: xref:System.Management.Automation.PSReference diff --git a/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md b/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md index 2f3f3948e5be..cc26d3d9bf65 100644 --- a/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md +++ b/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md @@ -1,7 +1,7 @@ --- description: Describes how to create and use a reference type variable. You can use reference type variables to permit a function to change the value of a variable that is passed to it. Locale: en-US -ms.date: 08/24/2018 +ms.date: 12/12/2024 online version: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_ref?view=powershell-7.5&WT.mc_id=ps-gethelp schema: 2.0.0 title: about_Ref @@ -10,18 +10,25 @@ title: about_Ref ## Short description -Describes how to create and use a reference type variable. You can use -reference type variables to permit a function to change the value -of a variable that is passed to it. +Describes how to create and use a reference type variable. ## Long description -You can pass variables to functions _by reference_ or _by value_. +You can pass variables to functions _by reference_ or _by value_. When you pass +a variable _by value_, you are passing a copy of the data. When you pass a +variable _by reference_, you are passing a reference to the original value. +This allows the function to change the value of the variable that is passed to +it.Reference types are created using `[ref]`, which is the type accelerator for +the `[System.Management.Automation.PSReference]` type. -When you pass a variable _by value_, you are passing a copy of the data. +The primary purpose of `[ref]` is to enable passing PowerShell variables by +reference to .NET method parameters marked as `ref`, `out`, or `in`. You can +also define your own PowerShell function that take `[ref]` type parameters. In +this usage, `[ref]` is applied to a _variable_, and the resulting `[ref]` +instance can be used to indirectly modify that variable's value. In the following example, the function changes the value of the variable passed -to it. In PowerShell, integers are value types so they are passed by value. +to it. In PowerShell, integers are value types so they're passed by value. Therefore, the value of `$var` is unchanged outside the scope of the function. ```powershell @@ -40,7 +47,7 @@ $var ``` In the following example, a variable containing a `Hashtable` is passed to a -function. `Hashtable` is an object type so by default it is passed to the +function. `Hashtable` is an object type so by default it's passed to the function _by reference_. When passing a variable _by reference_, the function can change the data and @@ -66,7 +73,7 @@ Test New Text The function adds a new key-value pair that persists outside of the function's scope. -### Writing functions to accept reference parameters +## Writing functions to accept reference parameters You can code your functions to take a parameter as a reference, regardless of the type of data passed. This requires that you specify the parameters type @@ -98,7 +105,7 @@ $var 3 ``` -### Passing references to .NET methods +## Passing references to .NET methods Some .NET methods may require you to pass a variable as a reference. When the method's definition uses the keywords `in`, `out`, or `ref` on a @@ -126,7 +133,7 @@ PS> $number 15 ``` -### References and scopes +## References and scopes References allow the value of a variable in the parent scope to be changed within a child scope. @@ -148,62 +155,96 @@ $i = 0;$iRef = 1 Only the reference type's variable was changed. -### Relationship between [ref] and System.Management.Automation.PSReference +## Using `[ref]` as a general-purpose object holder -`Ref` is both a type accelerator for `System.Management.Automation.PSReference` -(see [about_Type_Accelerators] for details) and a reserved keyword that -PowerShell [treats][2] [especially][1]. Hence, `ref` and `PSReference` are not -equivalents. The following script demonstrates their difference: +You can also use `[ref]` as a general-purpose object holder. In this usage, +`[ref]` is applied to a _value_ instead of a variable. Typically, the value is +an instance of a _value type_, like a number. In most scenarios you can use a +regular variable or parameter instead. However, this technique is useful in +scenarios where passing an explicit value holder is undesired (for brevity) or +not possible, such as in script-block parameter values. + +For example, you can use script-block parameter values to calculate the value +of **NewName** parameter of the `Rename-Item` cmdlet. The `Rename-Item` cmdlet +allows you to pipe items to it. The command run the script block passed to the +**NewName** for each item in the pipeline. The script block run in a child +scope. Modifying a variable in the caller's scope directly won't help and you +can't pass arguments to the script block in this context. + +In this example, the script block passed to the **NewName** parameter +increments the value of `$iRef` for each item in the pipeline. The script block +creates a new name by adding a number to the beginning of the filename. ```powershell -$x = 1 +$iRef = [ref] 0 +Get-ChildItem -File $setPath | + Rename-Item -NewName { '{0} - {1}' -f $iRef.Value++,$_.Name } +``` -$a = [ref] $x -$b = [System.Management.Automation.PSReference] $x -$c = [ref] $x +## Difference between `[ref]` and `[System.Management.Automation.PSReference]` -$x +=4 -$a.Value +=3 -$b.Value +=2 -$c.Value +=1 +A reference type variable is created using -$x, $a.Value, $b.Value, $c.Value | ForEach-Object { - Write-Output $PSItem -} -``` +Even though `[ref]` is a type accelerator for +`[System.Management.Automation.PSReference]`, they behave differently. + +- When you use `[ref]` to cast a variable, PowerShell creates reference object + that contains reference to the original instance of the variable. +- When you use `[System.Management.Automation.PSReference]` to cast a variable, + PowerShell creates reference object that contains a copy of the variable, + rather than a reference to the original instance. -The output of this script is: +For example, the following script creates a variable `$x` and two reference +objects. ```powershell -9 -9 -3 -9 +PS> $int = 1 +PS> $aRef = [ref] $int +PS> $bRef = [System.Management.Automation.PSReference] $int +PS> $int +1 +PS> $aRef, $bRef + +Value +----- + 1 + 1 ``` -The above script: +At this point, both reference object have the same value as `$int`. By adding +different values to the reference objects, we can see that `$aRef`, which was +created using `[ref]`, is a reference to the original instance of `$int`. +`$bRef` was created using `[System.Management.Automation.PSReference]` is a +copy of the variable. -- Creates an integer `$x` variable and assigns `1` to it. -- Creates pointers `$a` and `$c` of `[ref]` types and points them at `$x`. -- Creates pointer `$b` of `[PSReference]` type and points it, not at `$x`, but - a copy thereof, because PowerShell treats `[ref]` and `[PSReference]` - differently. -- Adds 4 to `$x`, 3 to `$a`'s value, 2 to `$b`'s value, and 1 to `$a`'s value. +```powershell +PS> $aRef.Value+=2 +PS> $bRef.Value+=5 +PS> $int +3 +PS> $aRef, $bRef -In the script above, `$x`, `$a.Value`, and `$c.Value` point to the same memory -location. They are the same, i.e., 1 + 4 + 3 + 1 = 9. But `$b.Value` refers to -a copy of `$x` at the time of its creation. Hence, it contains 1 + 2 = 3. +Value +----- + 3 + 6 +``` ## See also -- [about_Variables](about_Variables.md) -- [about_Environment_Variables](about_Environment_Variables.md) -- [about_Functions](about_Functions.md) -- [about_Script_Blocks](about_Script_Blocks.md) -- [about_Scopes](about_scopes.md) -- [about_Type_accelerators] - -[about_Type_accelerators]: about_Type_Accelerators.md - -[1]: https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/parser/ast.cs#L7983 -[2]: https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/parser/Compiler.cs#L6121 \ No newline at end of file +- [about_Variables][06] +- [about_Environment_Variables][01] +- [about_Functions][02] +- [about_Script_Blocks][04] +- [about_Scopes][03] +- [about_Type_Accelerators][05] +- [System.Management.Automation.PSReference][07] + + +[01]: about_Environment_Variables.md +[02]: about_Functions.md +[03]: about_scopes.md +[04]: about_Script_Blocks.md +[05]: about_Type_Accelerators.md +[06]: about_Variables.md +[07]: xref:System.Management.Automation.PSReference From fdac17c6c6d40817ba06badd06ba9d50071898e7 Mon Sep 17 00:00:00 2001 From: Sean Wheeler Date: Thu, 12 Dec 2024 14:35:01 -0600 Subject: [PATCH 3/3] Fix typo --- reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md | 6 +++--- reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md | 6 +++--- reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md b/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md index 2969894dd61f..e6fbdf737f3a 100644 --- a/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md +++ b/reference/5.1/Microsoft.PowerShell.Core/About/about_Ref.md @@ -211,11 +211,11 @@ Value 1 ``` -At this point, both reference object have the same value as `$int`. By adding +At this point, both reference objects have the same value as `$int`. By adding different values to the reference objects, we can see that `$aRef`, which was created using `[ref]`, is a reference to the original instance of `$int`. -`$bRef` was created using `[System.Management.Automation.PSReference]` is a -copy of the variable. +`$bRef`, which was created using `[System.Management.Automation.PSReference]`, +is a copy of the variable. ```powershell PS> $aRef.Value+=2 diff --git a/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md b/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md index 679de9a24584..24522019c862 100644 --- a/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md +++ b/reference/7.4/Microsoft.PowerShell.Core/About/about_Ref.md @@ -211,11 +211,11 @@ Value 1 ``` -At this point, both reference object have the same value as `$int`. By adding +At this point, both reference objects have the same value as `$int`. By adding different values to the reference objects, we can see that `$aRef`, which was created using `[ref]`, is a reference to the original instance of `$int`. -`$bRef` was created using `[System.Management.Automation.PSReference]` is a -copy of the variable. +`$bRef`, which was created using `[System.Management.Automation.PSReference]`, +is a copy of the variable. ```powershell PS> $aRef.Value+=2 diff --git a/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md b/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md index cc26d3d9bf65..741cfd80de35 100644 --- a/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md +++ b/reference/7.5/Microsoft.PowerShell.Core/About/about_Ref.md @@ -211,11 +211,11 @@ Value 1 ``` -At this point, both reference object have the same value as `$int`. By adding +At this point, both reference objects have the same value as `$int`. By adding different values to the reference objects, we can see that `$aRef`, which was created using `[ref]`, is a reference to the original instance of `$int`. -`$bRef` was created using `[System.Management.Automation.PSReference]` is a -copy of the variable. +`$bRef`, which was created using `[System.Management.Automation.PSReference]`, +is a copy of the variable. ```powershell PS> $aRef.Value+=2