diff --git a/src/System.Management.Automation/engine/parser/Compiler.cs b/src/System.Management.Automation/engine/parser/Compiler.cs index 0a68cb7951..7550a81d45 100644 --- a/src/System.Management.Automation/engine/parser/Compiler.cs +++ b/src/System.Management.Automation/engine/parser/Compiler.cs @@ -252,6 +252,9 @@ namespace System.Management.Automation.Language new Type[] { typeof(int), typeof(IEqualityComparer) }, null); + internal static readonly MethodInfo ByRefOps_GetByRefPropertyValue = + typeof(ByRefOps).GetMethod(nameof(ByRefOps.GetByRefPropertyValue), StaticFlags); + internal static readonly MethodInfo HashtableOps_Add = typeof(HashtableOps).GetMethod(nameof(HashtableOps.Add), StaticFlags); diff --git a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs index 52f85e372b..8025b116f1 100644 --- a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs +++ b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs @@ -5277,7 +5277,17 @@ namespace System.Management.Automation.Language return GenerateGetPropertyException(restrictions).WriteToDebugLog(this); } - expr = Expression.Property(targetExpr, propertyAccessor); + if (propertyAccessor.PropertyType.IsByRef) + { + expr = Expression.Call( + CachedReflectionInfo.ByRefOps_GetByRefPropertyValue, + targetExpr, + Expression.Constant(propertyAccessor)); + } + else + { + expr = Expression.Property(targetExpr, propertyAccessor); + } } else { diff --git a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs index 72a676dad1..fdcbaf98f5 100644 --- a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs +++ b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs @@ -1321,6 +1321,17 @@ namespace System.Management.Automation } } + internal static class ByRefOps + { + /// + /// There is no way to directly work with ByRef type in the expression tree, so we turn to reflection in this case. + /// + internal static object GetByRefPropertyValue(object target, PropertyInfo property) + { + return property.GetValue(target); + } + } + internal static class HashtableOps { internal static void AddKeyValuePair(IDictionary hashtable, object key, object value, IScriptExtent errorExtent) diff --git a/test/powershell/Language/Scripting/Adapter.Tests.ps1 b/test/powershell/Language/Scripting/Adapter.Tests.ps1 index db681192c4..2d7a13891e 100644 --- a/test/powershell/Language/Scripting/Adapter.Tests.ps1 +++ b/test/powershell/Language/Scripting/Adapter.Tests.ps1 @@ -108,3 +108,21 @@ Describe "Interface static members" -Tags "CI" { $obj.GetId() | Should -Be 100 } } + +Describe "ByRef property" -Tags "CI" { + + It "Get value from ByRef property" { + $list = [System.Collections.Generic.LinkedList[int]]::new() + $node = $list.AddLast(1) + + ## Get value through language binder. + $node.ValueRef | Should -Be 1 + + ## Get value through .NET adapter. + $property = $node.PSObject.Properties["ValueRef"] + $property.IsSettable | Should -BeFalse + $property.IsGettable | Should -BeTrue + $property.TypeNameOfValue | Should -BeExactly 'System.Int32&' + $property.Value | Should -Be 1 + } +}