From 950377faab65c997a1ac49af6f2f4968dd35fc73 Mon Sep 17 00:00:00 2001 From: "Mathias R. Jessen" Date: Fri, 30 Nov 2018 12:48:27 +0100 Subject: [PATCH] Conditionally mark getter/setter implementations virtual in generated classes (#8303) When implementing interfaces, PowerShell incorrectly produces non-virtual get/set methods for interface-defined properties. This commit adds a lookup method for interface-defined properties and marks get/set methods for properties with matching signatures virtual. --- .../engine/parser/PSType.cs | 18 ++++++++++++++++++ .../scripting.Classes.inheritance.tests.ps1 | 8 ++++++++ 2 files changed, 26 insertions(+) diff --git a/src/System.Management.Automation/engine/parser/PSType.cs b/src/System.Management.Automation/engine/parser/PSType.cs index 475f0cebb..a495ea5f5 100644 --- a/src/System.Management.Automation/engine/parser/PSType.cs +++ b/src/System.Management.Automation/engine/parser/PSType.cs @@ -434,6 +434,19 @@ namespace System.Management.Automation.Language return baseClass ?? typeof(object); } + private bool ShouldImplementProperty(string name, Type type) + { + foreach (var interfaceType in _typeBuilder.GetInterfaces()) + { + if (interfaceType.GetProperty(name, type) != null) + { + return true; + } + } + + return false; + } + public void DefineMembers() { // If user didn't provide any instance ctors or static ctor we will generate default ctor or static ctor respectively. @@ -576,6 +589,11 @@ namespace System.Management.Automation.Language // The property set and property get methods require a special set of attributes. var getSetAttributes = Reflection.MethodAttributes.SpecialName | Reflection.MethodAttributes.HideBySig; getSetAttributes |= propertyMemberAst.IsPublic ? Reflection.MethodAttributes.Public : Reflection.MethodAttributes.Private; + if (ShouldImplementProperty(propertyMemberAst.Name, type)) + { + getSetAttributes |= Reflection.MethodAttributes.Virtual; + } + if (propertyMemberAst.IsStatic) { backingFieldAttributes |= FieldAttributes.Static; diff --git a/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 b/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 index 57179022c..caebc7181 100644 --- a/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 +++ b/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 @@ -63,6 +63,14 @@ Describe 'Classes inheritance syntax' -Tags "CI" { [MyComparable].GetInterface("System.IComparable") | Should -Not -BeNullOrEmpty } + It 'can implement .NET interface properties' { + Add-Type -TypeDefinition 'public interface InterfaceWithProperty { int Integer { get; set; } }' + $C1 = Invoke-Expression 'class ClassWithInterfaceProperty : InterfaceWithProperty { [int]$Integer } [ClassWithInterfaceProperty]::new()' + $getter = $C1.GetType().GetMember('get_Integer') + $getter.ReturnType.FullName | Should -Be System.Int32 + $getter.Attributes -band [System.Reflection.MethodAttributes]::Virtual |Should -Be ([System.Reflection.MethodAttributes]::Virtual) + } + It 'allows use of defined later type as a property type' { class A { static [B]$b } class B : A {}