|
1 | 1 | ---
|
2 | 2 | description: Describes how you can use classes to create your own custom types.
|
3 | 3 | Locale: en-US
|
4 |
| -ms.date: 07/05/2023 |
| 4 | +ms.date: 07/13/2023 |
5 | 5 | online version: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_classes?view=powershell-7.4&WT.mc_id=ps-gethelp
|
6 | 6 | schema: 2.0.0
|
7 | 7 | title: about Classes
|
@@ -838,6 +838,83 @@ class MyComparableBar : bar, System.IComparable
|
838 | 838 | }
|
839 | 839 | ```
|
840 | 840 |
|
| 841 | +## NoRunspaceAffinity attribute |
| 842 | + |
| 843 | +A runspace is the operating environment for the commands invoked by PowerShell. |
| 844 | +This environment includes the commands and data that are currently present, and |
| 845 | +any language restrictions that currently apply. |
| 846 | + |
| 847 | +By default, a PowerShell class is affiliated with the **Runspace** where it's |
| 848 | +created. Using a PowerShell class in `ForEach-Object -Parallel` is not safe. |
| 849 | +Method invocations on the class are marshalled back to the **Runspace** where |
| 850 | +it was created, which can corrupt the state of the **Runspace** or cause a |
| 851 | +deadlock. |
| 852 | + |
| 853 | +Adding the `NoRunspaceAffinity` attribute to the class definition ensures that |
| 854 | +the PowerShell class is not affiliated with a particular runspace. Method |
| 855 | +invocations, both instance and static, use the **Runspace** of the running |
| 856 | +thread and the thread's current session state. |
| 857 | + |
| 858 | +The attribute was added in PowerShell 7.4. |
| 859 | + |
| 860 | +### Example - Class definition with Runspace affinity |
| 861 | + |
| 862 | +The `ShowRunspaceId()` method of `[UnsafeClass]` reports different thread Ids |
| 863 | +but the same runspace Id. Eventually, the session state is corrupted causing |
| 864 | +an error, such as `Global scope cannot be removed`. |
| 865 | + |
| 866 | +```powershell |
| 867 | +# Class definition with Runspace affinity (default behavior) |
| 868 | +class UnsafeClass { |
| 869 | + static [object] ShowRunspaceId($val) { |
| 870 | + return [PSCustomObject]@{ |
| 871 | + ThreadId = [Threading.Thread]::CurrentThread.ManagedThreadId |
| 872 | + RunspaceId = [runspace]::DefaultRunspace.Id |
| 873 | + } |
| 874 | + } |
| 875 | +} |
| 876 | +$unsafe = [UnsafeClass]::new() |
| 877 | +while ($true) { |
| 878 | + 1..10 | ForEach-Object -Parallel { |
| 879 | + Start-Sleep -ms 100 |
| 880 | + ($using:unsafe)::ShowRunspaceId($_) |
| 881 | + } |
| 882 | +} |
| 883 | +``` |
| 884 | + |
| 885 | +> [!NOTE] |
| 886 | +> This example runs in an infinite loop. Enter <kbd>Ctrl</kbd>+<kbd>C</kbd> to |
| 887 | +> stop the execution. |
| 888 | +
|
| 889 | +### Example - Class definition with NoRunspaceAffinity |
| 890 | + |
| 891 | +The `ShowRunspaceId()` method of `[SafeClass]` reports different thread and |
| 892 | +Runspace ids. |
| 893 | + |
| 894 | +```powershell |
| 895 | +# Class definition with NoRunspaceAffinity attribute |
| 896 | +[NoRunspaceAffinity()] |
| 897 | +class SafeClass { |
| 898 | + static [object] ShowRunspaceId($val) { |
| 899 | + return [PSCustomObject]@{ |
| 900 | + ThreadId = [Threading.Thread]::CurrentThread.ManagedThreadId |
| 901 | + RunspaceId = [runspace]::DefaultRunspace.Id |
| 902 | + } |
| 903 | + } |
| 904 | +} |
| 905 | +$safe = [SafeClass]::new() |
| 906 | +while ($true) { |
| 907 | + 1..10 | ForEach-Object -Parallel { |
| 908 | + Start-Sleep -ms 100 |
| 909 | + ($using:safe)::ShowRunspaceId($_) |
| 910 | + } |
| 911 | +} |
| 912 | +``` |
| 913 | + |
| 914 | +> [!NOTE] |
| 915 | +> This example runs in an infinite loop. Enter <kbd>Ctrl</kbd>+<kbd>C</kbd> to |
| 916 | +> stop the execution. |
| 917 | +
|
841 | 918 | ## Importing classes from a PowerShell module
|
842 | 919 |
|
843 | 920 | `Import-Module` and the `#requires` statement only import the module functions,
|
|
0 commit comments